前言
用户登录这个功能在现在越来越普遍,我也就研究了一下,本文主要讲登录这个功能中token的验证功能,本例使用的是vue框架,如何实现用户登录功能的token验证,以及整个的逻辑关系,也会将涉及到的其他知识点都讲清楚,让大家更容易更透彻的了解这个功能。废话不多说,看正文!
一、总体逻辑图
总体就是这样,接下来细说每个部分涉及的知识点和代码。
二、各环节涉及知识点以及代码
1.jwt(这里只说用法,至于为什么用它,详细可查官网)
用于生成token和token的解析验证
1.JWT的组成:
一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)、载荷(Payload)与签名(signature).
- JWT的组成:
一个JWT实际上就是一个字符串,它由三部分组成:头部(Header)、载荷(Payload)与签名(signature). - token生成:
//content:需要传递的主题信息,如:用户id
//secretOrPrivateKey:加密的key
jwt.sign({
var token = jwt.sign(content, secretOrPrivateKey, {
expiresIn: 10 // 多久过期,以s作为单位
});
- token解析验证
jwt.verify(token, secretOrPrivateKey, function (err, decode) {
if (err) { // 当token过期,或这是一个伪造的token,或这是无效的token时会触发此逻辑
console.log(err)
} else {
console.log(decode.msg);//得到token中传递的token主题信息,如:用户id
}
})
实际项目后端接口项目代码如下:
//app.js ,后端验证解析token接口,前端访问这个接口完整url为baseurl+'/validate'
const jwt = require('jsonwebtoken');
//创建服务器
let app=express();
//创建端口
app.listen(3000);
app.use(cors({
origin:['http://127.0.0.1:8080','http://localhost:8080']
}));
//挂载用户路由 前缀为/user
app.use('/user',userRouter);
//验证token的接口
let secret="mouchun.com";
app.get('/validate',(req,res)=>{
let token = req.headers['user-token']; //我们会把token放到我们自己设置的http的头authorization中,在这里可以直接拿到
console.log(token);
jwt.verify(token,secret,(err,decode)=>{ //验证token
if(err){
return res.json({
code:1,
data:'token失效了'
})
}else{
// token合法 在这里,需要把token的时效延长,
res.json({
code:0,
username:decode.username,
token:jwt.sign({username:'Fan'},secret,{ //合法时,我们需要重新生成一个token,我们每次切换路由,都要重新生成一个token
expiresIn:20
})
})
}
})
})
//user.js,后端登录接口,前端访问这个接口完整url为baseurl+'/user/v1/login'
const jwt = require('jsonwebtoken');
const router=express.Router();
//添加用户登录路由
router.post('/v1/login',(req,res)=>{
console.log(req.body);
var $uname=req.body.uname;
var $upwd=req.body.upwd;
console.log($uname,$upwd);
var sql='select*from lc_user where uname=? and upwd=?';
pool.query(sql,[$uname,$upwd],(err,result)=>{
if(err) throw err;
if(result.length>0){
// 把userId和其它相关信息加密成一个token,返回给前端
let userInfo = {
userId: result[0].uid,
}
// 生成token
let token = jwt.sign(userInfo, "mouchun.com", {
// expiresIn: "1000h"
expiresIn: "10s"
});
res.send({
code:200,
msg:"登录成功",
token:token
});
}else{
res.send({
code:0,
msg:"登录失败",
});
}
});
});
2.返回token并存入vuex做持久化
//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import {validate} from '../service/getdata'
//引入常量函数
import mutations from './mutations'
//vuex注册成为vue的插件
Vue.use(Vuex)
const state={
login: false, //是否登录
userInfo:null, //用户信息
userToken:"",//用户登录token
}
//通过构造函数创建一个vuex的store
export default new Vuex.Store({
//各个组件中共享的数据
//定义了应用状态的数据结构,其类型可以为string,number,bool,object
state,
//定义方法改变状态
mutations,
//发送异步请求
actions: {
//验证token方法
async validate({commit}){
let r = await validate(); //调用user.js中的validate方法,也就是调用验证接口
if(r.code === 0){
// commit('setUser',r.username)
this.userToken=r.token //我们说了,验证通过,或者每次切换路由时,都要重新生成token
}
return r.code === 0; //返回token是否失效,true或者false
}
},
//store的计算属性 第一次计算的结果会缓存
getters(){
},
modules: {
}
})
3.路由守卫
//router/index.js
export default new Router({
routes: [
{
path: '/login',
name: 'login',
component: login
},
{
path: '/',
name: 'Index',
component: Index,
//通过添加meta属性,来决定这个页面是否需要登录才能够查看,需要则加这个属性,否则不加
// meta:{
// needLogin:true
// }
}
]
})
//main.js
import router from './router'
import store from './store'
import axios from 'axios'
//添加到原型对象
Vue.prototype.axios=axios;
//每一次切换路由时,都执行这个导航守卫
router.beforeEach(async (to,from,next)=>{
//store.dispatch含有异步操作,数据提交至 actions ,可用于向后台提交数据
let isLogin = await store.dispatch('validate') //判断是否登录了
// needLogin 表示哪些路由需要在登录条件下才能访问
// console.log(to);
let needLogin = to.matched.some(match=>match.meta.needLogin)
if(needLogin){
//需要登录
if(isLogin){
//登录过了
next()
}else{
//没有登录
next('/login')
}
}else{
//不需要登录
if(isLogin && to.path === '/login'){ //如果你访问login页面,则给你跳到首页面,因为不需要登录
// next('/')
}else{
next()
}
}
})
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
4.axios请求拦截
//axios.js,axios的封装,具体可以查其他资料,这里主要展示请求拦截
import axios from "axios";
//请求拦截
axios.interceptors.request.use(
config => {
console.log('config',config);
// 从vuex读取token的值,给请求头添加laohu-token
if (store.state.userToken) {
config.headers['user-token'] = store.state.userToken;//如果存在token,将token放入请求头
}
return config
},
err => {
return Promise.reject(err)
})
总结
举个栗子:
- 发起任意请求axios.get/post(url)
- 跳至路由守卫,判断即将跳转的页面是否需要登录,并且现在是否已经登录,请求后端验证端口,返回响应
- 假如即将跳转页面需要登录,现在未登录跳转登录页
- 用户进行登录,请求后端登录接口,生成token,响应回前端
- 前端接收并保存
- 再次发起请求,路由守卫判断
- 假如即将跳转页面需要登录,现在已经登录,跳至axios请求拦截
- 携带token发起请求
- 后端接受,返回相应数据
综上所述:以上就是今天要讲的内容,本文仅仅简单介绍了token的使用,而还没有考虑token失效的情况,下一次再说!