使用Node.js和Express实现基于JWT的用户认证
首先我将使用Node + Express来尝试以下内容。
-
mongoDBに保存しているname/passでユーザ認証
- mongoDBに保存しているname/passでユーザ認証
-
- 認証OKならJWT形式のtokenを発行して返却
- JWTトークンを使って認証要のAPIにアクセス
我们将使用CUrl等方法来实现这些,而不是使用表单验证。
我会根据这个网站上的指示尝试实施。
所需之物
-
node
- node
-
- npm
-
- POSTman(api検証用のchrome extention)
- mongoDB
在服务器上进行实施的内容。
-
secureとsecure外のURL
- secureとsecure外のURL
-
- nameとpasswordによるユーザ認証
認証後にtokenを返却
ユーザは取得したtokenを保存、全リクエストに付与
tokenを検証、OKであればJSONで情報を返却
在Mac上安装MongoDB。
# install
brew install mongodb
# mongoDBを自動起動
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
创建项目
mkdir server.oauth
cd server.oauth
mkdir -p app/models
touch app/models/user.js
touch config.js
touch package.json
touch server.js
- app/
----- models/
---------- user.js
- config.js
- package.json
- server.js
包装. json
{
"name": "server.oauth",
"main": "server.js"
}
安装依赖库
npm install express body-parser morgan mongoose jsonwebtoken --save
# install
brew install mongodb
# mongoDBを自動起動
ln -sfv /usr/local/opt/mongodb/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mongodb.plist
mkdir server.oauth
cd server.oauth
mkdir -p app/models
touch app/models/user.js
touch config.js
touch package.json
touch server.js
- app/
----- models/
---------- user.js
- config.js
- package.json
- server.js
包装. json
{
"name": "server.oauth",
"main": "server.js"
}
安装依赖库
npm install express body-parser morgan mongoose jsonwebtoken --save
{
"name": "server.oauth",
"main": "server.js"
}
npm install express body-parser morgan mongoose jsonwebtoken --save
express is ポピュラーなNode Framework
mongoose is MongoDB用のO/Rmapper
morgan is ログをコンソールに出力する為に利用
body-parser is postされたパラメータのparser
jsonwebtoken is JWTの作成・検証用library
用户模型(app/models/user.js)
// get mongoose.Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// make user model and export
module.exports = mongoose.model('User', new Schema({
name: String,
password: String,
admin: Boolean
}));
配置文件(config.js)
module.exports = {
'secret': 'oauthServerSampleSecret',
'database': 'mongodb://localhost/server_oauth'
}
// get mongoose.Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// make user model and export
module.exports = mongoose.model('User', new Schema({
name: String,
password: String,
admin: Boolean
}));
module.exports = {
'secret': 'oauthServerSampleSecret',
'database': 'mongodb://localhost/server_oauth'
}
secret : JWTの作成と検証に使用する文字列、任意に変更する
database : mongoDBの接続URI
主要文件(server.js)
ひとまず初期設定と起動する最低限のみ記述
// =======================
// get instance we need
// =======================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');
var config = require('./config');
var User = require('./app/models/user');
// =======================
// configuration
// =======================
// server setting
var port = process.env.PORT || 8080;
// connect databse
mongoose.connect(config.database);
// application variables
app.set('superSecret', config.secret);
// config for body-parser
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());
// log request
app.use(morgan('dev'));
// =======================
// routes
// =======================
app.get('/', function(req, res) {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
// =======================
// start the server
// =======================
app.listen(port);
console.log('started http://localhost:' + port + '/');
试试启动
node server.js
-
起動したらブラウザを開き、http://localhost:8080/ にアクセス
// =======================
// get instance we need
// =======================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');
var config = require('./config');
var User = require('./app/models/user');
// =======================
// configuration
// =======================
// server setting
var port = process.env.PORT || 8080;
// connect databse
mongoose.connect(config.database);
// application variables
app.set('superSecret', config.secret);
// config for body-parser
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());
// log request
app.use(morgan('dev'));
// =======================
// routes
// =======================
app.get('/', function(req, res) {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
// =======================
// start the server
// =======================
app.listen(port);
console.log('started http://localhost:' + port + '/');
node server.js
-
- 起動したらブラウザを開き、http://localhost:8080/ にアクセス
成功すればHello…の文字が表示される
停止するにはコマンドラインで control+c
需要重新启动才能反映源代码更改。
如果觉得麻烦的话,可以使用 npm install -g nodemon,
然后运行 nodemon server.js,它能够检测更改并自动重新启动。
创建用于测试用户的URL(server.js)
// for create test user to db
app.get('/setup', function(req, res) {
var demo = new User({
name: 'demouser',
password: 'password', // TODO: encrypt password
admin: true
});
demo.save(function(err) {
if (err) throw err;
console.log('User saved successfully');
res.json({ success: true});
});
});
-
ブラウザから http://localhost:8080/setup にアクセス
// for create test user to db
app.get('/setup', function(req, res) {
var demo = new User({
name: 'demouser',
password: 'password', // TODO: encrypt password
admin: true
});
demo.save(function(err) {
if (err) throw err;
console.log('User saved successfully');
res.json({ success: true});
});
});
- ブラウザから http://localhost:8080/setup にアクセス
success: trueと表示されればDBに登録OK
确认是否已在mongoDB中注册。
mongo
use server_oauth
db.users.find()
要查看MongoDB的操作,请参考这里。
要查看数据库列表,请使用show dbs。
要查看表格列表,请使用show collections。
创建API(server.js)
-
API用のURLを作成
mongo
use server_oauth
db.users.find()
要查看MongoDB的操作,请参考这里。
要查看数据库列表,请使用show dbs。
要查看表格列表,请使用show collections。
-
- API用のURLを作成
API用のURLはexpress.Routerを使ってグルーピングして定義する
ユーザの一覧を取得するAPIを作成
// API ROUTES ================
var apiRoutes = express.Router();
// GET(http://localhost:8080/api/)
apiRoutes.get('/', function(req, res) {
res.json({ message: 'Welcome to API routing'});
});
// GET(http://localhost:8080/api/users)
apiRoutes.get('/users', function(req, res) {
User.find({}, function(err, users) {
if (err) throw err;
res.json(users);
});
});
// apply the routes to our application(prefix /api)
app.use('/api', apiRoutes);
-
- ブラウザより http://localhost:8080/api にアクセス
-
- 同じく http://localhost:8080/api/users にアクセス
ユーザの情報がjsonで取得できる
POSTmanを起動して上記のURLを発行しても確認できる
进行认证和创建令牌.
-
POST http://localhost:8080/api/authenticate を作成
- POST http://localhost:8080/api/authenticate を作成
-
- nameとpasswordを受け取ってユーザ認証のvalidate
- validならJWT tokenを作成してjsonで返却
// POST(http://localhost:8080/api/authenticate)
apiRoutes.post('/authenticate', function(req, res) {
// find db by posted name
User.findOne({
name: req.body.name
}, function(err, user) {
if (err) throw err;
// validation
if (!user) {
res.json({
success: false,
message: 'Authentication failed. User not found.'
});
return;
}
if (user.password != req.body.password) {
res.json({
success: false,
message: 'Authentication failed. Wrong password.'
});
return;
}
// when valid -> create token
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: '24h'
});
res.json({
success: true,
message: 'Authentication successfully finished.',
token: token
});
});
});
进行身份验证的测试
-
POSTmanを使って試す
- POSTmanを使って試す
methodをPOSTにする
Bodyタブを開き、x-www-form-urlencodedを選択
Key, valueを以下のようにセット
Key: name Value: demouser
Key: password Value: password
うまくいけばtokenが返却されていることがわかる

如果需要認證的頁面,進行保護,只要令牌匹配就可以通過。
-
認証Filterはexpress.Router().useで作成する
- 認証Filterはexpress.Router().useで作成する
-
- Filterを定義した以降に定義したURLはFilter通過後に動作する
コードの書く順序 が大事
// API ROUTES
var apiRoutes = express.Router();
// non secure api --------
// POST(http://localhost:8080/api/authenticate)
...
// Authentification Filter
apiRoutes.use(function(req, res, next) {
// get token from body:token or query:token of Http Header:x-access-token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// validate token
if (!token) {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({
success: false,
message: 'Invalid token'
});
}
// if token valid -> save token to request for use in other routes
req.decoded = decoded;
next();
});
});
// secure api --------
// GET(http://localhost:8080/api/)
...
// GET(http://localhost:8080/api/users)
...
// apply the routes to our application(prefix /api)
app.use('/api', apiRoutes);
使用令牌验证API的可用性
tokenを使わず、apiをコールするとエラーになる
-
POSTmanを使って、正しいname/passwordをPOST
取得できたtokenをコピー
POSTmanでtokenを含めた形でAPIをcall

-
- POSTmanを使って、正しいname/passwordをPOST
- 取得できたtokenをコピー

- POSTmanでtokenを含めた形でAPIをcall
