token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识。当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。
简单token的组成;uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,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会存储在内存,磁盘,或者数据库。
(3)JWT机制优缺点
优点:
缺点:
1、思路如下:
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模块
/**
* http://localhost:8089/blog/login
*/
router.post('/login',function(req,res){
let username = req.body.username;
let password = req.body.password;
console.log("用户名="+username)
pool.getConnection(function(err,conn){
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
})
}
conn.release(); //释放数据库连接对象
})
}
});
})
module.exports = router;
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.config.productionTip = false
Vue.prototype.$http = axios
// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to,from,next) => {
if(to.path === '/login'){
next();
}else{
let token = window.localStorage.token;
if(token === 'null' || token === '' || token === undefined){
next('/login')
}else{
next();
}
}
});
//添加请求拦截器
axios.interceptors.request.use(
config => {
if(store.state.token){
config.headers.common['token'] = store.state.token.token
}
return config;
},
error => {
//请求错误
return Promise.reject(error);
}
);
//添加响应拦截器
axios.interceptors.response.use(
response => {
return response;
},
error => {
if(error.response){
switch(error.response.status){
case 401:
localStorage.removeItem('token');
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath //登录成功后跳入浏览的当前页
}
})
}
}
}
)
new Vue({
el: '#app',
router,
store,
components: { App },
template: ' '
})
4、login.vue组件
5、home.vue组件
首页,跳转成功
6、store/index.js文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const key = 'token'
const store = new Vuex.Store({
state () {
return {
token: localStorage.getItem('token')?localStorage.getItem('token'):''
}
},
getters: {
getSortage: function(state) {
if(!state.token){
state.token =JSON.parse(localStorage.getItem(key))
}
return state.token
}
},
mutations: {
$_setStorage(state,value){
state.token = value
localStorage.setItem(key,JSON.stringify(value))
},
$_removeStorage(state){
state.token = null;
localStorage.removeItem(key)
}
}
})
export default store;
7、router/index.js文件
import Vue from 'vue'
import Router from 'vue-router'
import login from '@/components/login'
import home from '@/components/home'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: login
},
{
path: '/home',
name: 'home',
component: home
}
]
});
//导航守卫
//使用router.beforeEach注册一个全局前置守卫,判断用户是否登录
router.beforeEach((to,from,next)=>{
if(to.path === '/login'){
next();
}else{
let token = localStorage.getItem('Authorization');
if( token === 'null' || token === ''){
next('/login')
}else{
next();
}
}
});
export default router;
8、运行效果