现在比较流行的验证方式,是带着token的登录验证
原理
1. 登陆时,客户端发送用户名密码
2. 服务端验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端
3. 客户端储存token,一般都会存储在localStorage或者cookie里面(vue可以存储与vuex)
4. 客户端每次请求时都带有token,可以将其放在请求头里,每次请求都携带token
5. 服务端验证token,所有需要校验身份的接口都会被校验token,若token解析后的数据包含用户身份信息,则身份验证通过,返回数据
完整例子
下面来看一个比较完整的例子,有问题可以和我交流哦,我也挺菜的:
第一步,客户端发送用户名和密码; (一般是post过去)
第二步,验证用户名密码是否正确,校验通过就会生成一个有时效的token串,发送给客户端
if (data.toString() === req.body.pass){
// 登陆成功,添加token验证
let sid = req.body.pass + req.body.seccode; //密码 和 验证码组成其sid
let jwt = new JwtUtil(sid); //将用户sid传入,生成token
let token = jwt.generateToken();
res.send({status:200,msg:'登陆成功',token:token});
}else{
res.send({status:404,msg:'口令错误'})
}
第三步,客户端储存token,一般都会存储在localStorage或者cookie里面(这里我存储在vuex里面,进行统一管理)
第四步,客户端每次请求时都带有token,可以将其放在请求头里,每次请求都携带token
//使用vuex对全局token进行状态管理
this.$store.dispatch("set_token",res.data.token);
//设置:全局带token
this.$http.defaults.headers.common['token'] = this.$store.state.token;
store 里index.js:
import Vue from 'vue'
import Vuex from 'vuex'
//使用vuex
Vue.use(Vuex);
//一个store , Vuex.store的 实例
const store = new Vuex.Store({
state: {
token : ''
},
getters:{ // Getter相当于vue中的computed计算属性
getToken: (state) => {return state.token;}
},
mutations: {
set_token(state,ltoken) { //第一个参数是拿到state对象
localStorage.setItem('token',ltoken);
state.token = ltoken;
},
del_token(state) {
localStorage.removeItem('token');
state.token = '';
}
},
actions: { //注册actions,类似vue里面的methods
//通过这个修改state里面的值
// 可以直接用mutations修改,但是官方建议使用actions去调用mutations去修改
set_token(context,token) {
context.commit("set_token",token);
},
del_token(context){
context.commit("del_token");
}
}
})
export default
最后一步,服务端验证token,所有需要校验身份的接口都会被校验token,若token解析后的数据包含用户身份信息,则身份验证通过,返回数据
(这里,除了一些特定接口,不拦截之外,把拦截的 都需要进行验证)
(我这里是: /api/fr/articles 前台获取文章列表的接口不需要拦截; /api/imgCode 生成二维码的接口不需要拦截 /api/lone 登录发token的接口不需要拦截)
其他都需要拦截。
app.use(function (req, res, next){
//一共三个接口不需要拦截:
// /imgCode /lone /api/fr/articles
if (req.url != '/api/fr/articles' && req.url != '/api/imgCode' && req.url != '/api/lone') {
let token = req.headers.token;
let jwt = new JwtUtil(token);
let result = jwt.verifyToken();
console.log('result是:',result);
// 如果考验通过就next,否则就返回登陆信息不正确
if (result == 'err') {
console.log(result);
res.send({status: 403, msg: '登录已过期,请重新登录',res: result});
// res.render('login.html');
} else {
next();
}
} else {
next();
}
});
其中:jwt.js怎么写呢?参考于这篇文章: nodejs 基于token的身份验证
// 引入模块依赖
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
// 创建 token 类
class Jwt {
constructor(data) {
this.data = data;
}
//生成token
generateToken() {
let data = this.data;
let created = Math.floor(Date.now() / 1000);
let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_private_key.pem'));//私钥 可以自己生成
let token = jwt.sign({
data,
exp: created + 60 * 30,
}, cert, {algorithm: 'RS256'});
return token;
}
// 校验token
verifyToken() {
let token = this.data;
let cert = fs.readFileSync(path.join(__dirname, '../server/pem/rsa_public_key.pem'));//公钥 可以自己生成
let res;
try {
let result = jwt.verify(token, cert, {algorithms: ['RS256']}) || {};
let {exp = 0} = result, current = Math.floor(Date.now() / 1000);
if (current <= exp) {
res = result.data || {};
}
} catch (e) {
res = 'err';
}
return res;
}
}
module.exports = Jwt;
公私密钥对,一般可以选择openssl进行生成.