- 对于前后端分离模式的开发,大多使用 JWT(json web token)进行身份认证。
- token:当成功登录后,后端就返回一个凭据(本质是一个长长的字符串),有了这个凭据之后,后续再发请求接口,带上它就可以访问那些需要权限的接口。
- 流程图:
- 生成
token
基本步骤- 在项目中安装 jsonwebtoken :
npm i jsonwebtoken
- 加载模块
const jwt = require('jsonwebtoken')
- 在用户登录成功之后,调用
jwt.sign()
方法创建 token,有如下四个参数:- 参数1:必填,对象形式;希望在token中保存的数据
- 参数2:必填,字符串形式;加密的钥匙;后续验证token的时候,还需要使用
- 参数3:可选,对象形式;配置项,比如可以配置token的有效期(单位秒)
- 参数4:可选,函数形式;生成token之后的回调
- 生成的token前面,必须拼接
Bearer
这个字符串。
- 在项目中安装 jsonwebtoken :
- 参考代码:
// 后端--生成 token
const jwt = require('jsonwebtoken')
// 用户登陆方法
app.post('/login', (req, res) => {
// 其它代码......
// 调用生成 token 的方法
const tokenStr = jwt.sign({name: 'xxx' }, 'l-ddui', { expiresIn: 20 });
const token = 'Bearer ' + tokenStr
// 把 token 字符串 返回 给客户端浏览器
res.send({ code: 200, msg: '登录成功', token})
})
//前端--保存 token
localStorage.setItem('token',token)
// ajax 请求携带 token
$.ajax({
method: "",
url: "",
// 按照规范请求头传递 Authorization
headers: {
Authorization: localStorage.getItem('token'),
},
data: {...},
success: (res) => {
...
})
- 中间件验证
token
- 选择使用
express-jwt
第三方模块进行身份认证。从模块名可以看出,该模块是专门配合express使用的。 - 安装 express-jwt:
npm i express-jwt
- 选择使用
- 参考代码:
const jwt=require('express-jwt')
// app.use(jwt().unless());
// jwt() 用于解析 token ,并将 token 中保存的数据赋值给 req。user
// unless() 约定某个接口不需要身份认证
app.use(jwt({
secret:'l-ddui', // 生成 token 时的钥匙,必须和生成 token 时设置的统一
algorithms: ['HS256'] // 必填,加密算法,无需了解
}).unless({
path: ['/user/login', '/user/register'] // 除了这两个接口,其他都需要认证
}))
- 上述代码完成后,当一个接口请求到了服务器后,它会自动验证请求头中的 Authorization 字段了,并且会自动完成:
- 如果没有问题
- 将token中保存的数据赋值给req.user
- next( )
- 如果有问题,则抛出错误 next ( 错误信息 )
- 如果没有问题
- 错误处理 -- 中间件技术
- 在所有的路由最后,加入错误处理中间件,来提示token方面的错误。
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
// res.status(401).send('invalid token...');
res.status(401).send({ status: 1, message: '身份认证失败!' });
}
});
- 前端统一处理401错误(身份认证出错)
$(document).ajaxError(function( event, request, settings ) {
if(request.status === 401) {
// alert(request.responseJSON.msg)
return (location.href = './login.html')
}
})
- 前端携带 token
- 统一携带
$.ajaxSetup({
headers: {
Authorization: localStorage.getItem('token'),
}
})
- 选择性携带--(附登录拦截代码)
// $.ajaxPrefilter() 可以在调用 $.get() $.post() $.ajax() 之后,立即调用
$.ajaxPrefilter(function (options) {
// 开发环境服务器地址
let baseURL = 'http://127.0.0.1:10086'
// 手动添加根路径
options.url = baseURL + options.url
// 如果服务器路径包括 /my/ 则进行身份认证
if (options.url.indexOf('/my/') != -1) {
options.headers = {
Authorization: localStorage.getItem('token') || ''
}
// 登录拦截 -- complete 方法
options.complete = function (res) {
// console.log(res.responseJSON);
let obj = res.responseJSON
if (obj.status == 1 && obj.message == "身份认证失败!") {
// 销毁 token
localStorage.removeItem('token')
// 跳转到首页
location.href = '/login.html'
}
}
}
})