1. 通过 timeStamp, 超过时间,就用 refresh-token去更换 新的 token — 基于 vue 实现
在路由前置守卫处理
定义路由前置守卫
router.beforeEach((to, from, next) => {
next()
})
登录成功存时间戳
import { setItem } from '@/utils/storage.js'
setItem('TOKENDATE', Date.now())
进入路由之前进行判断token
import { getItem } from '@/utils/storage.js'
const tokenTimeOut = 5 * 60 * 1000
router.beforeEach((to, from, next) => {
console.log('判断token有没有过期')
const loginDate = getItem('TOKENDATE')
const currentDate = Date.now()
console.log((currentDate - loginDate) > tokenTimeOut)
})
封装请求方法
export const getToken = () => {
return request({
method: 'PUT',
url: '/v1_0/authorizations'
})
}
调用方法
router.beforeEach(async (to, from, next) => {
console.log('判断token有没有过期')
const loginDate = getItem('TOKENDATE')
const currentDate = Date.now()
if ((currentDate - loginDate) > tokenTimeOut) {
const res = await getToken()
store.commit('initUser', {
...store.state.user,
token: res.data.data.token
})
}
next()
})
请求拦截器判断携带refresh_token
request.interceptors.request.use(config => {
Toast.loading({
message: '加载中...',
forbidClick: true,
duration: 0
})
const { user } = store.state
if (user && user.token && config.url === '/v1_0/authorizations' && config.method === 'put') {
config.headers.Authorization = 'Bearer ' + user.refresh_token
} else if (user && user.token) {
config.headers.Authorization = 'Bearer ' + user.token
}
return config
})
在vue中 重置时间戳
mutations: {
initUser (state, data) {
state.user = data
setItem('HMTT_TOKEN', data)
setItem('TOKENDATE', Date.now())
}
}
2. token 过期或者失效,再通过 refresh_token 去获取新的 token ,基于 reacjs
Token: 访问令牌,通过这个token 就能够访问到需要权限的页面
- Token 有效时间都不会太长,一般就是 1-2个小时
- Token 过期的处理
? * 重新登录(适合PC端的管理系统)
? * 对于移动端资讯类的项目,用户体验不好
Refresh_token: 刷新令牌,没有访问的功能,通过刷新令牌能够获取到一个新的访问令牌,它的有效时间比较长。
-
为什么需要刷新令牌? – 1. 在项目中,客户端多次请求有权限的数据,都会携带 token.如果被抓包,用户的 token 就会暴露。 – 2. 如果黑客能够抓到 Refresh_token, 他也不太容易搞清楚,服务端是规定如何刷新 token 的,因为 https 协议都是**密文(http+SSL/TSL)**传输的
常用的处理流程:
2.1 code
request.js
import { Toast } from "antd-mobile";
import axios from "axios";
import localStorage from "local-storage";
import { TOKEN } from "@/store/constants";
import history from "./history";
import store from "@/store";
import { logOut, saveToken } from "@/store/action/login";
// 1. 创建新的 axios 实例
const baseURL = "http://geek.itheima.net/v1_0/";
const request = axios.create({
baseURL,
timeout: 5000,
});
// 2. 设置请求拦截器和响应拦截器
request.interceptors.request.use((config) => {
const token = localStorage.get(TOKEN)?.token;
if (token) {
config.headers["Authorization"] = "Bearer " + token;
}
return config;
});
request.interceptors.response.use(
(response) => {
return response.data;
},
async (error) => {
// 1. 网络异常
if (!error.response) {
Toast.fail("服务器繁忙,请稍后重试!", 1);
return Promise.reject(error); // return 响应错误,调用的函数不应该往下执行
}
const { response, config } = error;
// 2.服务器异常
if (error.response?.status !== 401) {
Toast.info(response.data.message);
return Promise.reject(error);
}
// 3. refresh_token 是不是被删除了?
const { refresh_token } = localStorage.get(TOKEN);
console.log("refresh", refresh_token);
if (!refresh_token) {
history.push("/login", { state: { from: history.location } });
return Promise.reject(error);
}
//4. 有 refreshToken,就拿着 refresh_token 去无感刷新
try {
const res = await axios({
method: "put",
url: baseURL + "authorizations", // 字符串拼接,不能多/;如果 baseURL, 通过 request, axios 会去处理
headers: {
Authorization: "Bearer " + refresh_token,
},
});
const newToken = {
token: res.data.data.token,
refresh_token,
};
// 设置完新的 token,请求后,要 return; 如果 没有设置成新的token,一起请求,会造成一直 401
store.dispatch(saveToken(newToken));
localStorage.set(TOKEN, newToken);
return request(config);
} catch (error) {
// refresh_token 过期了
store.dispatch(logOut());
history.push("/login", { from: history.location });
Toast.info("用户信息失效,请重新登录!", 1);
return Promise.reject(error); // 返回,是action中的dispatch的await不会一直等待
}
}
);
// 3. 导出该 axios 实例
export default request;
history.js
import { createBrowserHistory } from "history";
export default createBrowserHistory();
App.js
import AuthRoute from "@/components/AuthRoute/AuthRoute";
import React, { lazy, Suspense } from "react";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import history from "@/utils/history";
const Layout = lazy(() => import("./pages/Layout"));
const Login = lazy(() => import("./pages/Login"));
const EditProfile = lazy(() => import("./pages/Profile/EditProfile"));
const EditChat = lazy(() =>
import("./pages/Profile/EditProfile/components/EditChat")
);
function App() {
return (
<Router history={history}>
<div className="App">
<Suspense fallback={<div>...loading</div>}>
<Switch>
<Redirect exact from="/" to="/home" />
<Route path="/home" component={Layout} />
<Route path="/login" component={Login} />
<AuthRoute path="/profile/edit" component={EditProfile} />
<AuthRoute path="/profile/chat" component={EditChat} />
</Switch>
</Suspense>
</div>
</Router>
);
}
export default App;
|