JWT简介
JSON Web Token 简称 JWT,是一种认证机制,让后台知道请求是来自于受信的客户端。
作为一种跨域认证解决方案,有时我们也会称呼它为JSON Web令牌。
JWT 的原理
JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。
{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2018年7月1日0点0分"
}
以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名。
服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。
JWT练习
首先安装 jsonwebtoken:
npm install --save jsonwebtoken
然后写好前端页面和基础后台实现。
问题出现:我在用node写用户权限的时候,发现:如果我直接通过输入地址的方式访问一个需要登录才能访问的页面,比如下面这样:
这意味着该用户跳过登录页面,却可以直接访问这个页面,这就是问题呀!那么该怎么去解决这个bug,我们可以用 JSON Web Token。
流程上是这样的:
- 用户使用用户名密码来请求服务器
- 服务器进行验证用户的信息
- 服务器通过验证发送给用户一个token
- 客户端存储token,并在每次请求时附送上这个token值
- 服务端验证token值,并返回数据
摘自简书:https://www.jianshu.com/p/576dbf44b2ae
接下来进入正题。
1、用户首次登录时,后台将是否成功登录的信息与token一起返回给前台。
后台路由文件login.js:
...
//将下载好的资源包引入进来
var jwt=require("jsonwebtoken")
...
//通过查询数据库的用户数据,返回查询结果。如果该用户存在,数据的长度就不为0。
//然后不管是登陆成功还是失败,都给前台返回一个token,失败返回0,成功返回1。
col.find({uname:name,upwd:newpwd}).then((ok)=>{
// console.log(ok.length);
if(ok.length==0){
// 当用户登录失败,返回前端一个表示失败的token
let status={userStatus:0};
// 定义一个密钥/私钥 越乱越好
let mikey="skdhfkjvcxkhfdljdkuhlsdofyusajfg";
// 生成token 注意不要忘记引用
let newJwt=jwt.sign(status,mikey);
// 把生成的newJwt一起返回前台
res.send({msg:"登录失败",data:{loginid:10000,token:newJwt}});
}else{
// 用户登录成功的话,当然也要返回一个表示成功的token,其余步骤同上
let status={userStatus:1,uname:ok[0].uname}
let mikey="skdhfkjvcxkhfdljdkuhlsdofyusajfg";
let newJwt=jwt.sign(status,mikey)
res.send({msg:"登陆成功",data:{loginid:9527,uid:ok[0].uid,token:newJwt}})
}
})
2、前台将从后台生成的token保存在localStore中(或者cookie)。
window.localStorage.setItem("usertoken",ok.data.data.token)
3、然后在每次进入到权限验证页面,即我的index.vue组件页面时,先在localstore中拿到token:
let usertoken=window.localStorage.getItem("usertoken")
然后把这个数据发送给后台进行解密。我们需要携带着这个token 发送给后台,先封装一个请求,用来发送这个token参数。
var params=new URLSearchParams()
params.append("usertoken",usertoken)
//verifyTokenAxios是我封装的请求,用于向后台发送携带token验证信息
verifyTokenAxios(params).then((ok)=>{
console.log("index.vue中的OK",ok);
if(ok.data.data.userStatus==1){
alert("欢迎"+ok.data.data.uname)
}else{
alert("不好意思当前页面仅限会员使用!!请您登陆后在访问")
this.$router.push("/login")
}
}).catch((err)=>{
console.log("index.vue中的err",err);
})
4、后台需要解密这个token,判断用户是否登录过,然后返回信息给前端。
router.post("/verifytokenlogin",uE,(req,res)=>{
console.log("路由里面的token",req.body.usertoken);
let mikey="skdhfkjvcxkhfdljdkuhlsdofyusajfg"//与刚开始定义的私钥一致
// 解密token
jwt.verify(req.body.usertoken,mikey,(err,data)=>{
console.log("后台err",err)//正确就是null
console.log("后台data",data);
if(data.userStatus==1){
res.send({msg:"用户登陆过",data})
}else{
res.send({msg:"用户没有登陆过",data})
}
})
})
5、然后还需要注意一个事情:
在进入index.vue页面中,用了组件内导航守卫前置钩子来对是否存在token进行了判断。
// beforeRouteEnter 组件级路由守卫钩子 在进入组件前调用
beforeRouteEnter(to, from, next) {
// 在进入路由之前,判断是否存在token
if(!window.localStorage.getItem("usertoken")){
alert("您还没登录哦,请先登录")
next("/login");
}
next();
},
6、相关参数截图
前端Index.vue
后端Index.js