前后端分離后,后端只承擔(dān)api的功能吮便,傳統(tǒng)的使用session的認證方法帶來很大的不便:例如移動端app和PC端不能共用cookie等。
下面實例在node中用JWT做用戶認證
首先我們使用JWT simple這個庫區(qū)處理JWT的加密問題
npm install --save jwt-simple
var express = require('express');
var jwt = require('jwt-simple');
var app = express();
//設(shè)置密鑰
app.set('jwtTokenSecret', 'YOUR_SCRET_STRING');
首先第一件事是讓客戶端通過賬號密碼交換token,可以使用post拔恰,此處假設(shè)已經(jīng)得到了用戶名和密碼褪尝。
制造token
驗證用戶名和密碼通過后闹获,返回一個包含JWT的響應(yīng)。
var expires = moment().add('days', 7).valueOf()河哑;
var token = jwt.encode({
iss: user.id,
exp: expires,
}, app.get('jwtTokenSecret));
res.json({
token: token,
expires: expires,
user: user.toJSON()
})
檢驗token
為了驗證JWT避诽,我們需要寫出一些可以完成這些功能的中間件:
- 檢查附上的token
- 解密
- 驗證token的可用性
- 如果token是合法的,檢索里面的用戶璃谨,以及附加到請求的對象上沙庐。
我們來寫一個中間件的框架
var UserModel = require('../models/user');
var jwt = require('jwt-simple');
module.exports = function(req, res, next) {
//todo
}
為了獲得最大的可拓展性鲤妥,我們允許客戶端使用三個方法附加我們的token:
- 作為請求鏈接的參數(shù)(query)
- 作為主體的參數(shù)(body)
- 作為請求頭的參數(shù)(Header)(使用x-access-token)
下面是試圖檢索token的代碼
var token = (req.body && req.body.access_token) || (req.query && req.query.access_token) || req.header['x-access-token']
注意訪問req.body首先需要引入express.bodyParser()中間件
解析token
獲得token后,開始解析
if (token) {
try {
var decoded = jwt.decode(token, app.get('jwtTokenSecret'));
//todo handle token here
} catch (err) {
return next()
}
} else {
next()
}
如果解析失敗拱雏,我們使用next跳過路由棉安,這代表我們無法確定用戶合法性。
如果解析成功铸抑,我們獲得兩個屬性贡耽, iss
包含用戶ID,exp
包含過期時間鹊汛。我們先處理后者蒲赂,如果它過期了,直接拒絕刁憋。
if( decoded.exp <= Date.now()) {
res.end('Access token has expired', 400)
}
如果token合法滥嘴,我們可以從中檢索出用戶信息,并且附加到請求對象上面去:
User.findOne({ _id: decoded.iss }, function(err, user) {
req.user = user;
})
最后將這個中間件附加到路由里面:
var jwtauth = require('./jwtauth.js')
app.get('/something', [express.bodyParser(), jwtauth], function(req, res){
//do something
})
或者匹配一些路由
app.all('/api/*',[express.bodyParser(), jwtauth])
客戶端部分
客戶端再第一次獲得token后至耻,可以存儲在localStorage中若皱,請求的時候發(fā)出token
var token = window.localStorage.getItem('token');
if (token) {
$.ajaxSetup({
headers: {
'x-access-token': token
}
});
}