针对“无感知刷新Token示例简析”,我将提供完整的攻略,分为以下几个部分:背景介绍、方案设计、示例说明及参考文献。
背景介绍
随着Web应用不断扩大的规模和复杂度,用户态Token的安全性逐渐成为了不容忽视的问题,攻击者可以通过钓鱼、中间人等手段,窃取用户的Token,进而对用户的数据造成损失。为了解决这个问题,开发者可以通过刷新Token的方式,定期更换生成新的Token。但是在用户态下,对于token刷新的操作是不可避免的。
本文将介绍如何通过无感知的方式,刷新用户Token而不影响用户体验。
方案设计
为了实现无感知刷新Token的目的,我们可以采用以下的方案:
-
在每个需要用户验证的资源接口(比如API)中,都需要对Token进行校验,如果Token过期,则进行自动刷新。
-
在Token过期时,需要发出异步请求,在后端重新生成Token,并将新Token存储在数据库或Redis等存储介质中,并将新Token返回给前端。
-
在前端接收到新Token的响应后,我们需要将新Token更新到本地存储中。此时无需重载页面即可进行无感刷新Token,之后用户的操作需要使用新Token(否则操作会一直被forbidden)。
示例说明
以JavaScript的Fetch请求为例,以下提供两种实现无感知刷新Token的示例:
- 使用Fetch Interceptor
import auth from './auth'
// 构建fetch拦截器
class FetchInterceptor {
static instance
// 获取拦截器实例
static getInstance () {
if (!this.instance) {
this.instance = new FetchInterceptor()
}
return this.instance
}
// 请求拦截器,用于自动注入请求头
interceptRequest (url, config) {
// 从本地存储中获取token
const token = auth.getToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return [url, config]
}
// 响应拦截器,自动刷新过期token
async interceptResponse (response) {
// 访问受限,判断是否token过期
const data = await response.json()
if (response.status === 401) {
// 过期了,发起刷新token的请求,将新的token存储到本地存储中
const newToken = await auth.refreshToken()
// 存储新的token
auth.saveToken(newToken)
// 构建新的请求headers
const headers = new Headers(response.headers)
headers.set('Authorization', `Bearer ${newToken}`)
// 构建新的响应对象
let newResponse = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers
})
return newResponse
}
// 非401请求直接返回
return response
}
}
// 处理完 intercept 链之后的 request 函数
async function intercept (url, config) {
const interceptors = [FetchInterceptor.getInstance()]
let request = [url, config]
// 按照顺序来执行拦截器
for (let i = 0; i < interceptors.length; i++) {
const [newUrl, newConfig] = await interceptors[i].interceptRequest(...request)
request = [newUrl, newConfig]
}
const response = await fetch(...request)
// 针对返回值做hack处理
for (let i = interceptors.length - 1; i >= 0; i--) {
const newResponse = await interceptors[i].interceptResponse(response)
response = newResponse || response
}
return response
}
function get (url) {
return intercept(url, { method: 'GET' })
}
export default {
get
}
- 使用Axios Interceptor
import axios from 'axios'
import auth from './auth'
// 初始化Axios实例
const instance = axios.create()
// 拦截器配置
instance.interceptors.request.use(
(config) => {
// 从本地存储中获取token
const token = auth.getToken()
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)
instance.interceptors.response.use(
(response) => {
return response
},
async (error) => {
const {
config,
response: { status }
} = error
if (status === 401) {
// 获取新的token
const newToken = await auth.refreshToken()
// 更新本地token
auth.saveToken(newToken)
// 重新加载原有请求
config.headers.Authorization = `Bearer ${newToken}`
return instance.request(config)
}
return Promise.reject(error)
}
)
export default instance
参考文献
文章内容参考了以下资料:
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:无感知刷新Token示例简析 - Python技术站