用session实现用户识别 有两缺点
(1)其实session也是通过cookie实现的,大致原理是:当pc向服务器发送请求,服务器就想pc的浏览器发送一个随机字符串来标识这台主机,然后如果pc登录成,服务器就在后台的账本上记住,这个随机字符和对应的用户id,
cookie每次请求会自动携带,所以只要cookie不变,服务器就会知道,这个随机字符串就对应的某个用户。但是由于没次请求就会自动带上cookie,这有一定安全问题,例如:当你之前登录过某个银行网站,他们使用session的方式,你再在某个钓鱼网站点击别人定制的链接,就可能在钓鱼网站登录了银行网站执行某些操作,因为这种不受浏览器同源策略限制,而使用token,他一般不会自动提交,就没有这个问题了,钓鱼网站无法获得token
(2)token是不存储在服务器上的,所以不用存储空间,但是他需要解密,加密,
它实际上token就是一段服务发送给pc加密的有用户id的字符串,只有服务器才能服务器才能解密,而且不是cookie,了解了基本原理就可以知道他的实现步骤了
例如登录:
(1)当用户请求端口的时候,服务器检测是否有token,说登录过,返回相应页面数据
(2)请求登录接口时候,验证用户名和密码是否正确,如果正确,返回 存储用户id或者用户名的加密token,给pc
(3)前端查看有没有token,有的话,存储到localStorage,
(3)之后前端每次请求读取localStorage的token都携带上
只要localStorage在那么就一直是登录状态
代码如下:
token.js
let jwt = require('jsonwebtoken') //生成token
const { expressjwt } = require('express-jwt') // 解码token
let jwtScrect = 'xdfdfsdfdsxfd' //签名
//登录接口 生成token的方法
let setToken = function(user_name, user_id, expiresIn) {
//expiresln 设置token过期的时间
//{ user_name: user_name, user_id: user_id } 传入需要解析的值( 一般为用户名,用户id 等)
return jwt.sign(
{ user_name: user_name, user_id: user_id },
jwtScrect,
{ expiresIn }
) // 返回一个token
}
//各个接口需要验证token的方法
let getToken = function(token) {
if (!token) {
console.log('token是空的')
return 0
} else {
//第二种 改版后的
let info = null
try {
info = jwt.verify(token, jwtScrect)
} catch (e) {
return 0
}
//解析返回的值(sign 传入的值) 返回一个token的明码
return info
}
}
// 解析token
let decodeToken = expressjwt({
credentialsRequired: true, //需要校验
secret: jwtScrect, // 加密秘钥
algorithms: ['HS256'] // 加密方式
}).unless({
path: [
'/admin',
'/login',
/^\/static/,
'/captcha',
'/',
'/userinfo', // 单独校验
'/favicon.ico',
/^\/img/,
/^\/data/
] // 不需要校验的路径
// path: ["/admin","/login"/^(\/admin|\/|\/login)/],
})
// 处理解析错误
// 定义错误中间件
// middleware/errorhandler.js
function errorToken(err, req, res, next) {
//console.log("token出现错误这一步->>", err, err.name, "《-----");
let code = 500
let message = 'Internal Server Error'
// token解析的错误
if (err.name === 'UnauthorizedError') {
code = 401
message = 'token 解析错误'
}
res.statusCode = code
res.send({
status: code,
message
})
}
//导出
let errorHandler = (module.exports = {
setToken,
getToken,
decodeToken,
errorToken
})
其中:1.setToken是生成一个加密的token字符串,我这里定义的参数是(用户名,用户id,过期时间) ,
登录成功发送给token前端的时候使用,
2.getToken是将前端发过来的Token,解密为之前的参数(用户名,用户id,过期时间)
这个是用于返回用户id或者用户名这些值的,或者在数据库通过id查询用户更多信息时候使用
3.decodeToken是配置token,及那些路径我们不验证token,配置加密方式,加密的密钥等
4.errorToken就是配置,当需要验证token的路径,没有token,或者token是错的,我们如何错误提示
3.4是中间件,要使用.use安装
// 导入token
let {
decodeToken,
errorToken,
} = require("./utility/token");
// 解析toke
app.use(decodeToken);
// 处理错误
// 错误中间件写在最后
app.use(errorToken);
setToken:登录成功后返回token
res.json({
code: 1,
msg: "登陆成功",
data: results[0].username,
token: token.setToken(
results[0].username,
results[0].id,
"3600s"
), // 设置头
});
getToken:验证是否登录返回用户名
// 有登陆过
res.json({
code: 1,
data: {
username: token.getToken(req.headers["authorization"].split(" ")[1])
.user_name,
},
msg: "已经登陆",
});