AuthとJWT、MongoDB、およびPostgresでエクスプレス
認証は、常に理解し、達成するトリッキーです.実装の概念と高レベルについてより深くする場合は、次の記事を読んでください. Authentication and Authorization in Concept Implmenting Auth at a High Level 基本的には、Authを持つAPIを持つために以下のようにビルドする必要があります. 優先データベースとのインタフェースへのユーザモデル /新しいユーザを作成するためのサインアップルート /ユーザーが存在することを確認するログインルート、パスワードが正しく、すべてのチェックアウト /我々が使うどんなクッキーも破壊するためのログアウト経路 どのようなバックエンドのフレームワークや言語を使用すると、上記は本質的に目標です.私たちはこのチュートリアルのために急行を使用して、目的の終わり結果を得る2つの方法を示すためにMongoDBとPostgresを使用します.
始める つのフォルダを作成します.
エクスプレスアプリセットアップ
両方のフォルダについては、次のようにします. 必要なフォルダを作成する 次のファイルを作成する
次のライブラリをインストールします
バックエンドフレームワーク
Dotenvは私たちを使用することができます.env file env変数を定義する
Corsは我々のCors頭をセットします(我々のフロントエンドを含む他のウェブサイトはAPIに要求をすることができます)
モーガンはトラブルシューティングを助けて、問題を特定します
クッキーパーサは、クッキーが入ってくるリクエストに含まれていることを解析し、REQに保存します.クッキー クリエイトア env . env
utils/corsで.私たちがセキュリティを強化したいならば、我々のCorsヘッダーを構成するために以下を加えましょう.
最初のルートで我々のhomecontrollerをつくってください 中でミドルウェアを登録するための機能を作成しましょう サーバで次のようにします.js
https://github.com/Alex-Merced-Templates/express_starter
蒙古 マングースを取り付ける MongoDBで無料Mongoデータベースを取得します.comまたはmongoをインストールし、ローカルのmongoサーバーを実行すると、URLをあなたの
接続
インサイド
ユーザモデル
ファイルを作る
藤堂モデル
Authコントローラ bcryptとjwtのインストール クリエイト 私たちのミドルウェアでAuthControllerを登録してください
Authミドルウェア
正しいユーザーだけがアクセスできるようにし、TODOを修正するには、ユーザがログインしてログインしているかどうかをチェックする必要があります.これは、送信されたトークンクッキーをチェックすることによってすべて行うことができます.我々は、我々が我々が必要とする認可を望むどんなルートででも使うことができるカスタムメイドのミドルウェアをつくります!
TODOコントローラ それから、我々のミドルウェアでルータを登録してください
この点までコードを見ることができます.
https://github.com/Alex-Merced-Templates/express_starter/tree/mongo
今すぐPostgresで! シーケンスをインストール データベースドライバのインストール いくつかのデータベースプロバイダからPostgresデータベースを取得するか、Postgresサーバーをコンピュータ上で実行します
接続
インサイド
ユーザモデル
ファイルを作る
藤堂モデル
Authコントローラ bcryptとjwtのインストール クリエイト 私たちのミドルウェアでAuthControllerを登録してください
Authミドルウェア
正しいユーザーだけがアクセスできるようにし、TODOを修正するには、ユーザがログインしてログインしているかどうかをチェックする必要があります.これは、送信されたトークンクッキーをチェックすることによってすべて行うことができます.我々は、我々が我々が必要とする認可を望むどんなルートででも使うことができるカスタムメイドのミドルウェアをつくります!
TODOコントローラ それから、我々のミドルウェアでルータを登録してください
この点までコードを見ることができます.
https://github.com/Alex-Merced-Templates/express_starter/tree/postgres
さらに取る
ネオ4 JやAlanGodbのようなグラフデータベースで再びこれを達成しようとすると、両方の無料層と自分のクラウドデータベースサービスを持っているので、なぜ! Neo4J Tutorial ArangoDB Tutorial
始める
express_mongo
and express_postgres
我々は、各フォルダに別のアプリケーションを作成されます.各フォルダのセットアップは同じです.エクスプレスアプリセットアップ
両方のフォルダについては、次のようにします.
mkdir connection models controllers utils
touch server.js connection/db.js utils/middleware.js utils/cors.js controllers/HomeController.js
次のライブラリをインストールします
npm install express dotenv cors morgan cookie-parser
バックエンドフレームワーク
Dotenvは私たちを使用することができます.env file env変数を定義する
Corsは我々のCors頭をセットします(我々のフロントエンドを含む他のウェブサイトはAPIに要求をすることができます)
モーガンはトラブルシューティングを助けて、問題を特定します
クッキーパーサは、クッキーが入ってくるリクエストに含まれていることを解析し、REQに保存します.クッキー
.env
and .gitignore
ファイルPORT = 4000
ギティノー/node_modules
.env
// whitelist of URLS that can make a request to your server
// to allow all urls, whitelist should have "*" as its first element
const whitelist = ["*"]
// if whitelist starts with "*" then all traffic allowed, otherwise if origin url is not in whitelist, request is blocked.
const corsOptions = {
origin: function (origin, callback) {
if (whitelist[0] === "*") {
callback(null, true)
} else {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error("Not allowed by CORS"))
}
}
},
}
module.exports = corsOptions
controllers/HomeController
// New Express Router
const router = require("express").Router()
// Router Middleware
// Router Routes
router.get("/", (req, res) => {
res.json({ response: "server is working" })
})
// Export Router
module.exports = router
utils/middleware.js
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
const HomeController = require("../controllers/HomeController")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {}
// move on to next middleware
next()
}
const registerMiddleware = app => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
}
module.exports = registerMiddleware
require("dotenv").config() // load variables from .env
const express = require("express")
const registerMiddleware = require("./utils/middleware")
// Grab any ENV variables to be used, set default values in case .env file missing
const { PORT = 3000 } = process.env
// The Application Object
const app = express()
// registerMiddleware
registerMiddleware(app)
// Server listener
app.listen(PORT, () => console.log(`listening on port ${PORT}`))
また、私たちがこれまでに出したコードを持つためにこのテンプレートを使用することができます.蒙古
.env
. また、あなたが好きであるどんなストリングでもありえる秘密と呼ばれている変数を定義してください.PORT=4000
DATABASE_URL=mongodb+srv://username:[email protected]/databaseName?retryWrites=true&w=majority
SECRET=thisIsMySecret
*上記のデータベースURLは例ですが、独自のURLを取得する必要があります接続
インサイド
connection/db.js
require("dotenv").config()
const mongoose = require("mongoose")
// get env variables
const { DATABASE_URL } = process.env
// connect to mongoose
mongoose.connect(DATABASE_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
// Connection Messages
mongoose.connection
.on("open", () => console.log("Connected to Mongo"))
.on("close", () => console.log("Disconnected from Mongo"))
.on("error", error => console.log(error))
// export connection
module.exports = mongoose
ユーザモデル
ファイルを作る
models/User.js
// import connection, grab schema and model
const { Schema, model } = require("../connection/db")
// define user schema
const userSchema = new Schema(
{
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
role: { type: String, required: true, default: "general" },
},
{ timestamps: true }
)
// define user model
const User = model("User", userSchema)
// export User
module.exports = User
藤堂モデル
models/Todo.js
// import connection, grab schema and model
const { Schema, model } = require("../connection/db")
// define Todo schema
const todoSchema = new Schema(
{
message: { type: String, required: true },
completed: { type: Boolean, default: false },
username: { type: String, required: true },
},
{ timestamps: true }
)
// define Todo model
const Todo = model("Todo", todoSchema)
// export Todo
module.exports = Todo
すべてのコントローラーが容易にそれらにアクセスできるようになりました.utils/middleware.js
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: { User, Todo },
}
// move on to next middleware
next()
}
const registerMiddleware = app => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
}
module.exports = registerMiddleware
Authコントローラ
npm install bcryptjs jsonwebtoken
controllers/AuthController.js
// New Express Router
const router = require("express").Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
require("dotenv").config();
// Router Middleware
//signup route "/auth/signup"
router.post("/signup", async (req, res) => {
try {
// grab model from context
const User = req.context.models.User;
// hash the password
req.body.password = await bcrypt.hash(req.body.password, 10);
// create new User
const user = await User.create(req.body);
// respond, send back user without password
const response = { username: user.username, role: user.role };
res.json(response);
} catch (error) {
res.status(400).json({ error });
}
});
// login route "/auth/login"
router.post("/login", async (req, res) => {
try {
console.count("login")
// grab model from context
const User = req.context.models.User;
console.count("login")
// grab username and password
const { username, password } = req.body;
// see if user exists
const user = await User.findOne({ username });
if (user) {
// check if password matches
const doesItMatch = await bcrypt.compare(password, user.password);
if (doesItMatch) {
// remove password from user data
const userData = { username: user.username, role: user.role };
// sign token
const token = jwt.sign(userData, process.env.SECRET);
// respond
res.cookie("token", token, { httpOnly: true }).json(userData);
} else {
throw "Passwords do not match";
}
} else {
throw "User Does Not Exist";
}
} catch (error) {
res.status(400).json({ error });
}
});
// logout "/auth/logout"
router.get("/logout", async (req, res) => {
res.clearCookie("token").json({response: "You are Logged Out"})
})
// Export Router
module.exports = router;
utils/middleware.js
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
const AuthController = require("../controllers/AuthController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: {User, Todo}
}
// move on to next middleware
next()
}
const registerMiddleware = (app) => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
app.use("/auth", AuthController) // register homecontroller routes for "/auth" urls
}
module.exports = registerMiddleware
これで、ログイン、ログインとログアウト!それでは、ユーザが彼らのためにTODOSを作成できるルートを作成しましょう.Authミドルウェア
正しいユーザーだけがアクセスできるようにし、TODOを修正するには、ユーザがログインしてログインしているかどうかをチェックする必要があります.これは、送信されたトークンクッキーをチェックすることによってすべて行うことができます.我々は、我々が我々が必要とする認可を望むどんなルートででも使うことができるカスタムメイドのミドルウェアをつくります!
utils/auth.js
require("dotenv").config();
const jwt = require("jsonwebtoken");
const isUserLoggedIn = async (req, res, next) => {
try {
// check if the token is in the cookies
const { token = false } = req.cookies;
if (token) {
// verify token
const payload = await jwt.verify(token, process.env.SECRET);
// add payload to request
req.payload = payload;
// move on
next();
} else {
throw "Not Logged In";
}
} catch (error) {
res.status(400).json({ error });
}
};
module.exports = isUserLoggedIn
TODOコントローラ
controllers/TodoController
// New Express Router
const router = require("express").Router();
const isUserLoggedIn = require("../utils/auth");
// Index Route "/todo", returns all todos for that user
router.get("/", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
res.json(await Todo.find({ username: req.payload.username }));
} catch (error) {
res.status(400).json({ error });
}
});
// Create Route "/todo", creates a new todo
router.post("/", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
req.body.username = req.payload.username;
res.json(await Todo.create(req.body));
} catch (error) {
res.status(400).json({ error });
}
});
// update Route "/todo/:id", updates a todo
router.put("/:id", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
const id = req.params.id;
res.json(await Todo.findByIdAndUpdate(id, req.body, { new: true }));
} catch (error) {
res.status(400).json({ error });
}
});
// destroy Route "/todo/:id", deletes a todo
router.delete("/:id", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
const id = req.params.id;
res.json(await Todo.findByIdAndRemove(id));
} catch (error) {
res.status(400).json({ error });
}
});
//export router
module.exports = router;
utils/middleware
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
const AuthController = require("../controllers/AuthController")
const TodoController = require("../controllers/TodoController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: {User, Todo}
}
// move on to next middleware
next()
}
const registerMiddleware = (app) => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
app.use("/auth", AuthController) // register homecontroller routes for "/auth" urls
app.use("/todo", TodoController) // register todocontroller routes for "/todo" urls
}
module.exports = registerMiddleware
conGATS今すぐ認証を使用してmongo/Expressで藤堂APIを構築している!この点までコードを見ることができます.
https://github.com/Alex-Merced-Templates/express_starter/tree/mongo
今すぐPostgresで!
npm install sequalize
npm install pg pg-hstore
PORT=4000
DATABASE_URL=postgres://username:password@localhost:5432/express_app
SECRET=thisIsMySecret
*上記のデータベースURLは例ですが、独自のURLを取得する必要があります接続
インサイド
connection/db.js
require("dotenv").config();
const { Sequelize } = require("sequelize");
// connect to database
const sequelize = new Sequelize(process.env.DATABASE_URL)
// check if connection established
async function checkConnection() {
try {
await sequelize.authenticate();
console.log("Connection has been established successfully.");
} catch (error) {
console.error("Unable to connect to the database:", error);
}
}
checkConnection()
//export connection
module.exports = sequelize;
ユーザモデル
ファイルを作る
models/User.js
// import connection, grab schema and model
const sequalize = require("../connection/db")
const {DataTypes} = require("sequelize")
// Define User Model
const User = sequalize.define("User", {
username: {type: DataTypes.STRING, allowNull: false, unique: true},
password: {type: DataTypes.STRING, allowNull: false},
role: {type: DataTypes.STRING, allowNull: false, defaultValue: "general"}
}, {tableName: "users", timestamps: true})
// create the table if doesn't exist
async function createTable(){
await User.sync()
}
createTable()
// export User
module.exports = User
藤堂モデル
models/Todo.js
// import connection, grab schema and model
const sequalize = require("../connection/db")
const {DataTypes} = require("sequelize")
// Define Todo Model
const Todo = sequalize.define("Todo", {
username: {type: DataTypes.STRING, allowNull: false},
message: {type: DataTypes.STRING}
}, {tableName: "todos", timestamps: true})
// create the table if doesn't exist
async function createTable(){
await Todo.sync()
}
createTable()
// export User
module.exports = Todo
すべてのコントローラーが容易にそれらにアクセスできるようになりました.utils/middleware.js
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: { User, Todo },
}
// move on to next middleware
next()
}
const registerMiddleware = app => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
}
module.exports = registerMiddleware
Authコントローラ
npm install bcryptjs jsonwebtoken
controllers/AuthController.js
// New Express Router
const router = require("express").Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
require("dotenv").config();
// Router Middleware
//signup route "/auth/signup"
router.post("/signup", async (req, res) => {
try {
// grab model from context
const User = req.context.models.User;
// hash the password
req.body.password = await bcrypt.hash(req.body.password, 10);
// create new User
const user = await User.create(req.body);
// respond, send back user without password
const response = { username: user.username, role: user.role };
res.json(response);
} catch (error) {
res.status(400).json({ error });
}
});
// login route "/auth/login"
router.post("/login", async (req, res) => {
try {
console.count("login");
// grab model from context
const User = req.context.models.User;
console.count("login");
// grab username and password
const { username, password } = req.body;
// see if user exists
const user = await User.findOne({ where: { username } });
if (user) {
// check if password matches
const doesItMatch = await bcrypt.compare(password, user.password);
if (doesItMatch) {
// remove password from user data
const userData = { username: user.username, role: user.role };
// sign token
const token = jwt.sign(userData, process.env.SECRET);
// respond
res.cookie("token", token, { httpOnly: true }).json(userData);
} else {
throw "Passwords do not match";
}
} else {
throw "User Does Not Exist";
}
} catch (error) {
res.status(400).json({ error });
}
});
// logout "/auth/logout"
router.get("/logout", async (req, res) => {
res.clearCookie("token").json({ response: "You are Logged Out" });
});
// Export Router
module.exports = router;
utils/middleware.js
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
const AuthController = require("../controllers/AuthController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: {User, Todo}
}
// move on to next middleware
next()
}
const registerMiddleware = (app) => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
app.use("/auth", AuthController) // register homecontroller routes for "/auth" urls
}
module.exports = registerMiddleware
これで、ログイン、ログインとログアウト!それでは、ユーザが彼らのためにTODOSを作成できるルートを作成しましょう.Authミドルウェア
正しいユーザーだけがアクセスできるようにし、TODOを修正するには、ユーザがログインしてログインしているかどうかをチェックする必要があります.これは、送信されたトークンクッキーをチェックすることによってすべて行うことができます.我々は、我々が我々が必要とする認可を望むどんなルートででも使うことができるカスタムメイドのミドルウェアをつくります!
utils/auth.js
require("dotenv").config();
const jwt = require("jsonwebtoken");
const isUserLoggedIn = async (req, res, next) => {
try {
// check if the token is in the cookies
const { token = false } = req.cookies;
if (token) {
// verify token
const payload = await jwt.verify(token, process.env.SECRET);
// add payload to request
req.payload = payload;
// move on
next();
} else {
throw "Not Logged In";
}
} catch (error) {
res.status(400).json({ error });
}
};
module.exports = isUserLoggedIn
TODOコントローラ
controllers/TodoController
// New Express Router
const router = require("express").Router();
const isUserLoggedIn = require("../utils/auth");
// Index Route "/todo", returns all todos for that user
router.get("/", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
res.json(await Todo.findAll({ where: { username: req.payload.username } }));
} catch (error) {
res.status(400).json({ error });
}
});
// Create Route "/todo", creates a new todo
router.post("/", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
req.body.username = req.payload.username;
res.json(await Todo.create(req.body));
} catch (error) {
res.status(400).json({ error });
}
});
// update Route "/todo/:id", updates a todo
router.put("/:id", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
const id = req.params.id;
res.json(await Todo.update(req.body, { where: { id } }));
} catch (error) {
res.status(400).json({ error });
}
});
// destroy Route "/todo/:id", deletes a todo
router.delete("/:id", isUserLoggedIn, async (req, res) => {
try {
const Todo = req.context.models.Todo;
const id = req.params.id;
res.json(await Todo.destroy({ where: { id } }));
} catch (error) {
res.status(400).json({ error });
}
});
//export router
module.exports = router;
utils/middleware
const express = require("express")
const cookieParser = require("cookie-parser")
const morgan = require("morgan")
const cors = require("cors")
const corsOptions = require("./cors")
// import controllers
const HomeController = require("../controllers/HomeController")
const AuthController = require("../controllers/AuthController")
const TodoController = require("../controllers/TodoController")
// import models
const User = require("../models/User")
const Todo = require("../models/Todo")
// function to create context property in every request with shared data
const applicationContext = (req, res, next) => {
// data to share can be added in this object
req.context = {
models: {User, Todo}
}
// move on to next middleware
next()
}
const registerMiddleware = (app) => {
app.use(cors(corsOptions)) // cors headers
app.use(cookieParser()) // parse cookies
app.use(express.json()) // parse json bodies
app.use(morgan("tiny")) // logging
app.use(applicationContext) // add context object to request
app.use("/", HomeController) // register homecontroller routes for "/" urls
app.use("/auth", AuthController) // register homecontroller routes for "/auth" urls
app.use("/todo", TodoController) // register todocontroller routes for "/todo" urls
}
module.exports = registerMiddleware
あなたは今、認証を持つpostgress/expressでtodo APIを構築しました!この点までコードを見ることができます.
https://github.com/Alex-Merced-Templates/express_starter/tree/postgres
さらに取る
ネオ4 JやAlanGodbのようなグラフデータベースで再びこれを達成しようとすると、両方の無料層と自分のクラウドデータベースサービスを持っているので、なぜ!
Reference
この問題について(AuthとJWT、MongoDB、およびPostgresでエクスプレス), 我々は、より多くの情報をここで見つけました https://dev.to/alexmercedcoder/auth-with-express-with-jwt-mongodb-and-postgres-4a5テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol