<<使用jwt来做验证登陆>>
在之前所说的jwt = json web token,是一个开源的标准规范(RFC 7519),定义了一个坚实(compact)并且独立(self-contained)的利用JSON对象作为在两方之间信息安全传递的方法,信息之所以能够被验证而且能够被信任是因为经过了电子签名。JWTs可以通过使用secret(比如HMAC算法)或者使用经过rsa的公/私秘钥对。
---Compact:由于jwt体积很小,因此jwts可以通过URL或者当作POST方法的一个参数,或者在HTTP头部进行发送。并且体积小意味着传输速度更快
---Self-contained:负载部分(payload)包含着需要的关于用户的所有信息,避免了多次访问数据库。
<<什么时候该使用JSON web token>>
---Authentication: 这是JWT最常用的场景,只要用户一旦登陆上了,每一个随后的请求将会包含着jwt,运行用户在token在被允许的情况下访问路由,服务和资源。目前而言,单点登录(Single Sign On)是一个广泛运用jwt的场景,因为jwt的小体积和具体功能能够运用于不同的域名之下。
---Information Exchange: Jwt对于信息的安全传递来说非常好用。因为jwt有签名的原名-比如,用公钥秘钥对,我们能够确定发送者的真实身份。而且,当签名利用头部(payload)和荷载(payload)部分生成时候,我们可以确认内容没有被窜改
<<jwt和passport结合使用>>
有了jwt,要如何运用?
通常而言,可以通过第三方库,比如passport库,结合jwt来使用,目前npm网站上的passport-jwt的包可以满足目前的要求。
首先进行相关包的安装
npm install --save express body-parser passport jsonwebtoken passport-jwt lodash
其中安装包中的body-parser lodash在博客内的其他文章中也有说明
安装好之后,先对相关包进行引入
const express = require('express');
const app = new express();
const bodyParse = require('body-parser');
app.use(passport.initialize());
app.use(bodyParse.urlencoded({
extended:true
}))
//parse application/json
app.use(bodyParse.json());
然后设置服务器的简单路由和启动
app.get('/', function(req, res){
res.send('hello');
});
app.listen(3000, function(){
console.log('Your Express App is Running now');
})
之后引入passport相关库
const jwt = require('jsonwebtoken');
const passport = require('passport');
const passportJWT = require('passport-jwt');
const _ = require('lodash');
设置一个路由为/login,代表登陆,由于目前没有使用数据库,先暂时在本文件内定义用户数据
let users = [
{
id: 1,
name: 'lily',
password: 'lilycollins'
},
{
id: 2,
name: 'test',
password: 'test'
}
];
app.post('/login', function(req, res){
//还不慌将其写完
})
之后,对passport-jwt进行配置
let jwtOptions = {};
jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
//ExtractJwt.fromAuthHeader() is replaced by ExtractJwt.fromAuthHeaderAsBearerToken()
jwtOptions.secretOrKey = 'tasmanianDevil';
//The secretOrKey is the secret that our tokens will be signed with
let strategy = new JwtStrategy(jwtOptions,function(jwt_payload,next){
console.log('Payload received', jwt_payload);
//usually this would be a database call
let user = users[_.findIndex(users, {id:jwt_payload.id})];
if(user){
next(null,user);
}else{
next(null,user);
}
})
passport.use(strategy);
之后,完善路由/login里面的匹配规则,如果用户成功登陆,即账号和密码都匹配上,就生成相应的jwt,此时app.post('/login')具体应该如下,具体token由jwt.sign方法生成
app.post('/login', function(req, res){
if(req.body.name && req.body.password){
let name = req.body.name;
let password = req.body.name;
}
//usually this would be a database call
let name = req.body.name;
let user = users[_.findIndex(users,{name: name})];
//find the user in users whose name = name
if(!user){
res.status(401).json({message:'no such user'})
}
if(user.password === req.body.password){
//from now on, we will identify the user by the id
// and the id is the only personalized value that goes
// into our token
let payload = {id: user.id};
let token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({message: "ok", token: token});
}else{
res.status(401).json({message: "password did not match"})
}
})
此时从postman应该可以得到相应的token了,为了验证token,添加一个路由/secret
app.get('/secret',passport.authenticate('jwt',{session:false}),function(req,res){
res.json('Ok now, You can not see this without a token');
});
通过postman将token附属在authorization中,然后进行get操作,直接就可收到信息
Ok now, You can not see this without a token。
但是,在使用过程中,严禁将敏感信息添加到jwt中去,容易被恶意第三方截取,密码应该通过加密方法之后在进行发送。jwt在本例子中的要点是成功登陆之后,ExtractJwt.fromAuthHeaderAsBearerToken()从头部中抓取必要信息,之后生成token。
PS:感谢JonathanMH的文章给予的指导: JonathanMH博客链接
网友评论