Vue项⽬中实现⽤户登录及token验证
⼀、什么是token
token的意思是“令牌”,是服务端⽣成的⼀串字符串,作为客户端进⾏请求的⼀个标识。当⽤户第⼀次登录后,服务器⽣成⼀个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,⽆需再次带上⽤户名和密码。
简单token的组成;uid(⽤户唯⼀的⾝份标识)、time(当前时间的时间戳)、sign(签名,token的前⼏位以哈希算法压缩成的⼀定长度的⼗六进制字符串。为防⽌token泄露)。
⼆、token的作⽤
1、防⽌表单重复提交:主要的理念是,客户端初始化的时候(⼀般就是刚刚进⼊页⾯的时候)就调⽤后端代码,后端代码⽣成⼀个token,返回给客户端,客户端储存token(可以在前台使⽤Form表单中使⽤隐藏域来存储这个Token,也可以使⽤cookie),然后就将request(请求)中的token与(session)中的token进⾏⽐较
2、⽤来作⾝份验证:
(1)⾝份认证概述
由于HTTP是⼀种没有状态的协议,它并不知道是谁访问了我们的应⽤。这⾥把⽤户看成是客户端,客户端使⽤⽤户名还有密码通过了⾝份验证,不过下次这个客户端再发送请求时候,还得再验证⼀下。
通⽤的解决⽅法是:当⽤户请求登录的时候,如果没有问题,在服务端⽣成⼀条记录,在这个记录⾥可以说明登录的⽤户是谁,然后把这条记录的id发送给客户端,客户端收到以后把这个id存储在cookie⾥,下次该⽤户再次向服务端发送请求的时候,可以带上这个cookie,这样服务端会验证⼀下cookie⾥的信息,看能不能在服务端这⾥到对应的记录,如果可以,说明⽤户已经通过了⾝份验证,就把⽤户请求的数据返回给客户端。
以上所描述的过程就是利⽤session,那个id值就是sessionid。我们需要在服务端存储为⽤户⽣成的session,这些session会存储在内存,磁盘,或者数据库。
:使⽤token机制的⾝份验证⽅法,在服务器端不需要机制的⾝份认证:使⽤
(2)基于token机制的⾝份认证
存储⽤户的登录记录。流程如下:
1. 客户端使⽤⽤户名和密码请求登录。
2. 服务端收到请求,验证⽤户名和密码。
3. 验证成功后,服务端会⽣成⼀个token,然后把这个token发送给客户端。
4. 客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)⾥。
5. 客户端每次向服务端发送请求的时候都需要带上服务端发给的token。
6. 服务端收到请求,然后去验证客户端请求⾥⾯带着token,如果验证成功,就向客户端返回请求的数据。
三、Vue项⽬中实现⽤户登录及token验证
1、思路如下:
(1) 第⼀次登录的时候,前端调后端的登陆接⼝,发送⽤户名和密码
(2) 后端收到请求,验证⽤户名和密码,验证成功,就给前端返回⼀个token
(3) 前端拿到token,将token存储到localStorage和vuex中,并跳转路由页⾯
(4) 前端每次跳转路由,就判断 localStroage 中有⽆ token ,没有就跳转到登录页⾯,有则跳转到对应路由页⾯
(5) 每次调后端接⼝,都要在请求头中加token
(6) 后端判断请求头中有⽆token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
(7) 如果前端拿到状态码为401,就清除token信息并跳转到登录页⾯
2、后台接⼝(node.js)的实现
(1)安装JWT:  npm install jsonwebtoken --save
JWT(Json Web Token)是⼀种⾝份验证及授权⽅案,简单的说就是客户端调⽤ api 时,附带上⼀个由 api 端颁发的 token,以此来验证调⽤者的授权信息。
(2)JWT的常⽤函数:
A、sign(payload, secretOrPrivateKey, [options, callback])
B、verify(token, secretOrPublicKey, [options, callback])
C、decode(token [, options])
(3)后台代码实现:
var express = require('express');
var router = express.Router();
var pool = require('../config/blogdb.js')
const jwt = require('jsonwebtoken'); //引⼊jwt模块
/**
* localhost:8089/blog/login
*/
router.post('/login',function(req,res){
let username = req.body.username;
let password = req.body.password;
console.log("⽤户名="+username)
if(err){
console.log('连接数据库失败!')
}else{
let data=[username,password]
let sql = "select * from admin where username= ? and password = ?";          conn.query(sql,data,function(error,results){
if(error){
console.log(error)
}
if(results != null){ //若查询结果不为空
const payload = { //定义token的有限载荷
name: results.username
}
const secret = 'deyun' //给定密钥
//定义token
const token = jwt.sign(payload,secret,{
'expiresIn':1440});// 设置过期时间
res.json({ //将响应信息转换为json格式
success: true,
message: 'Enjoy your token',
token: token
})
}
})
}
});
})
(4)JWT机制优缺点
优点:
⽀持跨域访问: Cookie是不允许垮域访问的,这⼀点对Token机制是不存在的,前提是传输的⽤户认证信息通过HTTP头传输.
⽆状态(也称:服务端可扩展⾏):Token机制在服务端不需要存储session信息,因为Token ⾃⾝包含了所有登录⽤户的信息,只需要在客户端的cookie或本地介质存储状态信息.
更适⽤CDN: 可以通过内容分发⽹络请求你服务端的所有资料(如:javascript,HTML,图⽚等),⽽你的服务端只要提供API即可.
去耦:不需要绑定到⼀个特定的⾝份验证⽅案。Token可以在任何地⽅⽣成,只要在你的API被调⽤的时候,你可以进⾏Token⽣成调⽤即可.
更适⽤于移动应⽤: 当你的客户端是⼀个原⽣平台(iOS, Android,Windows 8等)时,Cookie是不被⽀持的(你需要通过Cookie容器进⾏处理),这时采⽤Token认证机制就会简单得多。
CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
性能: ⼀次⽹络往返时间(通过数据库查询session信息)总⽐做⼀次HMACSHA256计算的Token验证和解析要费时得多.
基于标准化:你的API可以采⽤标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的⽀持(如:Firebase,Google, Microsoft)
缺点:
JWT 的最⼤缺点是,由于服务器不保存 session 状态,因此⽆法在使⽤过程中废⽌某个 token,或者更改 token 的权限。也就是说,⼀旦 JWT 签发了,在到期之前就会始终有效,除⾮服务器部署额外的逻辑。
JWT 本⾝包含了认证信息,⼀旦泄露,任何⼈都可以获得该令×××的所有权限。为了减少盗⽤,JWT 的有效期应该设置得⽐较短。对于⼀些⽐较重要的权限,使⽤时应该再次对⽤户进⾏认证。
为了减少盗⽤,JWT 不应该使⽤ HTTP 协议明码传输,要使⽤ HTTPS 协议传输。
三、前端Vue实现
1、创建项⽬:vuetokendemo,⽬录结构如下
2、给项⽬安装vuex模块
3、main.js⽂件
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import store from './store' //导⼊store
Vue.prototype.$http = axios
// 导航守卫
// 使⽤ router.beforeEach 注册⼀个全局前置守卫,判断⽤户是否登陆router.beforeEach((to,from,next) => {
if(to.path === '/login'){
next();
}else{session数据错误是什么意思
let token = ken;
if(token === 'null' || token === '' || token === undefined){
next('/login')
}else{
next();
}
}
});
//添加请求
quest.use(
config => {
if(ken){
config.headersmon['token'] = ken
}
return config;
},
error => {
//请求错误
ject(error);
}
);
//添加响应
sponse.use(
response => {
return response;
},
error => {
sponse){
sponse.status){
case 401:
path: '/login',
query: {
redirect: router.currentRoute.fullPath //登录成功后跳⼊浏览的当前页            }
})
}
}
}
)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。