1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 无感刷新token(从后端到前端整个流程)

无感刷新token(从后端到前端整个流程)

时间:2018-08-16 19:24:50

相关推荐

无感刷新token(从后端到前端整个流程)

前言

token刷新是前端安全中必要的一部分,本文从后端到前端整个流程介绍如何实现无感刷新token。页面代码亲自实现并跑通,请放心食用。如需源码,请在评论区留言。码字不易,点赞支持!!!

一、实现思路

通过长短token实现:短token用来请求应用数据,长token用于获取新的短token(长短指的是过期时间)

二、后端设计

后端存有两个字段,分别保存长短token,并且每一段时间更新他们短token过期,返回 returncode:104;长token过期,返回 returncode: 108;请求成功返回returncode: 0;请求头中pass用来接收客户端长token,请求头中authorization用来接收客户端短token

1. 搭建node服务

创建一个新文件夹,通过vscode打开,运行:

npm init -y

安装koa

npm i koa -s

新建index.js

const Koa = require('koa')const app = new Koa();app.use(async(ctx,next)=>{ctx.body = "这是一个应用中间件";await next()})app.listen(4000,() => {console.log('server is listening on port 4000')})

安装nodemon

npm i nodemon -g

配置package.json

"dev":"nodemon index.js",

运行:npm run dev 访问:127.0.0.1:4000,可以看到页面显示这是一个应用中间件

2. 使用路由中间件

安装

npm i koa-router -S

新建routes/index.js

const router = require("koa-router")();let accessToken = "init_s_token"; //短tokenlet refreshToken = "init_l_token"; //长token/* 5s刷新一次短token */setInterval(() => {accessToken = "s_tk" + Math.random();}, 5000);/* 一小时刷新一次长token */setInterval(() => {refreshToken = "l_tk" + Math.random();}, 600000);/* 登录接口获取长短token */router.get("/login", async (ctx) => {ctx.body = {returncode: 0,accessToken,refreshToken,};});/* 获取短token */router.get("/refresh", async (ctx) => {//接收的请求头字段都是小写的let { pass } = ctx.headers;if (pass !== refreshToken) {ctx.body = {returncode: 108,info: "长token过期,重新登录",};} else {ctx.body = {returncode: 0,accessToken,};}});/* 获取应用数据1 */router.get("/getData", async (ctx) => {let { authorization } = ctx.headers;if (authorization !== accessToken) {ctx.body = {returncode: 104,info: "token过期",};} else {ctx.body = {code: 200,returncode: 0,data: { id: Math.random() },};}});/* 获取应用数据2 */router.get("/getData2", async (ctx) => {let { authorization } = ctx.headers;if (authorization !== accessToken) {ctx.body = {returncode: 104,info: "token过期",};} else {ctx.body = {code: 200,returncode: 0,data: { id: Math.random() },};}});module.exports = router;

修改index.js

//删除app.use(async(ctx,next)=>{ctx.body = "这是一个应用中间件";await next()})//新增const index = require('./routes/index')app.use(index.routes(),index.allowedMethods())

3. 跨域处理

安装

npm i koa2-cors

使用:

const cors = require('koa2-cors');app.use(cors());

最终index.js文件

const Koa = require('koa')const app = new Koa();const index = require('./routes/index')const cors = require('koa2-cors');app.use(cors());app.use(index.routes(),index.allowedMethods())app.listen(4000,() => {console.log('server is listening on port 4000')})

目录结构:

重新运行 npm run dev,这时服务端已准备好

三、前端设计

1. 定义使用到的常量

新建 config/constant.js

/* localStorage存储字段 */export const ACCESS_TOKEN = "s_tk"; //短tokenexport const REFRESH_TOKEN = "l_tk"; //长token、/* HTTP请求头字段 */export const AUTH = "Authorization"; //存放短tokenexport const PASS = "PASS"; //存放长token

新建 config/returnCodeMap.js

// 在其它客户端被登录export const CODE_LOGGED_OTHER = 106;// 重新登陆export const CODE_RELOGIN = 108;// token过期export const CODE_TOKEN_EXPIRED = 104;//接口请求成功export const CODE_SUCCESS = 0;

2. 封装服务

关键点:将token过期的请求,借助Promise将请求存进数组中,让这个Promise一直处于pending状态(即不调用resolve),当获取到新的短token时,再逐个重新请求

如果不保持promise链,就会当成一个新的请求,页面内容不会更新

安装axios

npm i axios -S

新建 service/index.js

import axios from "axios";import { refreshAccessToken, addSubscriber } from "./refresh";import { clearAuthAndRedirect } from "./clear";import {CODE_LOGGED_OTHER,CODE_RELOGIN,CODE_TOKEN_EXPIRED,CODE_SUCCESS,} from "../config/returnCodeMap";import { ACCESS_TOKEN, AUTH } from "../config/constant";const service = axios.create({baseURL: "//127.0.0.1:4000",timeout: 30000,});service.interceptors.request.use((config) => {let { headers } = config;const s_tk = localStorage.getItem(ACCESS_TOKEN);s_tk &&Object.assign(headers, {[AUTH]: s_tk,});return config;},(error) => {return Promise.reject(error);});service.interceptors.response.use((response) => {let { config, data } = response;//retry:第一次请求过期,接口调用refreshAccessToken,第二次重新请求,还是过期则reject出去let { retry } = config;/* 延续Promise链 */return new Promise((resolve, reject) => {if (data["returncode"] !== CODE_SUCCESS) {if ([CODE_LOGGED_OTHER, CODE_RELOGIN].includes(data.returncode)) {clearAuthAndRedirect();} else if (data["returncode"] === CODE_TOKEN_EXPIRED && !retry) {config.retry = true;addSubscriber(() => resolve(service(config)));refreshAccessToken();} else {return reject(data);}} else {resolve(data);}});},(error) => {return Promise.reject(error);});export default service;

新建 service/refresh.js

import service from "./index";import { ACCESS_TOKEN, REFRESH_TOKEN, PASS } from "../config/constant";import { clearAuthAndRedirect } from "./clear";let subscribers = [];let pending = false; //同时请求多个过期链接,保证只请求一次获取短tokenexport const addSubscriber = (request) => {subscribers.push(request);};export const retryRequest = () => {subscribers.forEach((request) => request());subscribers = [];};export const refreshAccessToken = async () => {if (!pending) {try {pending = true;const l_tk = localStorage.getItem(REFRESH_TOKEN);if (l_tk) {/* 重新获取短token */const { accessToken } = await service.get("/refresh",Object.assign({}, { headers: { [PASS]: l_tk } }));localStorage.setItem(ACCESS_TOKEN, accessToken);retryRequest();}return;} catch (e) {clearAuthAndRedirect();return;} finally {pending = false;}}};

新建 service/clear.js

import {ACCESS_TOKEN} from '../config/constant'/* 清除长短token,并定位到登录页(在项目中使用路由跳转) */export const clearAuthAndRedirect = () =>{localStorage.removeItem(ACCESS_TOKEN)window.location.href = '/login'}

3. 使用

这里使用react实现,使用vue效果一样

//App.js

import { useState } from "react";import service from "./service/index.js";import { ACCESS_TOKEN, REFRESH_TOKEN } from "./config/constant";const App = () => {const [data1, setData1] = useState();const [data2, setData2] = useState();const getData = () => {service.get("/getData").then((res) => {setData1(res.data.id);});service.get("/getData2").then((res) => {setData2(res.data.id);});};const getToken = () => {service.get("/login").then((res) => {//存储长tokenlocalStorage.setItem(REFRESH_TOKEN, res.refreshToken);//存储短tokenlocalStorage.setItem(ACCESS_TOKEN, res.accessToken);});};return (<div>{data1}--{data2}<button onClick={getData}>按钮</button><button onClick={getToken}>登录</button></div>);};export default App;

运行项目,查看效果

先点击登录按钮获取长短token,过5秒再去点击按钮,获取应用数据(上面后端设置了短token 5s过期)

页面数据能更新,并且refresh接口只调用一次

网络安全成长路线图

这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成hei客大神,这个方向越往后,需要学习和掌握的东西就会越来越多,以下是学习网络安全需要走的方向:

# 网络安全学习方法

​ 上面介绍了技术分类和学习路线,这里来谈一下学习方法:

​ ## 视频学习

​ 无论你是去B站或者是油管上面都有很多网络安全的相关视频可以学习,当然如果你还不知道选择那套学习,我这里也整理了一套和上述成长路线图挂钩的视频教程,完整版的视频已经上传至CSDN官方,朋友们如果需要可以点击这个链接免费领取。网络安全重磅福利:入门&进阶全套282G学习资源包免费分享!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。
相关阅读
无感刷新token方法

无感刷新token方法

2021-10-06

vue无感刷新token

vue无感刷新token

2022-06-17

axios无感刷新token

axios无感刷新token

2020-09-07

实现双token无感刷新

实现双token无感刷新

2020-04-19