使用Node.js和Express实现基于JWT的用户认证

首先我将使用Node + Express来尝试以下内容。

    • mongoDBに保存しているname/passでユーザ認証

 

    • 認証OKならJWT形式のtokenを発行して返却

 

    JWTトークンを使って認証要のAPIにアクセス

我们将使用CUrl等方法来实现这些,而不是使用表单验证。

我会根据这个网站上的指示尝试实施。

所需之物

    • node

 

    • npm

 

    • POSTman(api検証用のchrome extention)

 

    mongoDB

在服务器上进行实施的内容。

    • 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

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'
}

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/ にアクセス

成功すれば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 にアクセス

success: trueと表示されればDBに登録OK

确认是否已在mongoDB中注册。

mongo
use server_oauth
db.users.find()

要查看MongoDB的操作,请参考这里。
要查看数据库列表,请使用show dbs。
要查看表格列表,请使用show collections。

创建API(server.js)

    • 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 を作成

 

    • 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を使って試す

methodをPOSTにする
Bodyタブを開き、x-www-form-urlencodedを選択
Key, valueを以下のようにセット

Key: name Value: demouser
Key: password Value: password

うまくいけばtokenが返却されていることがわかる

Kobito.4BNXEm.png

如果需要認證的頁面,進行保護,只要令牌匹配就可以通過。

    • 認証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をコールするとエラーになる
Kobito.MpW1qa.png

    • POSTmanを使って、正しいname/passwordをPOST

 

    取得できたtokenをコピー
Kobito.O6Xf7O.png

    POSTmanでtokenを含めた形でAPIをcall
Kobito.onSu9R.png

bannerAds