Nextjs+Strapi+Redux:如何在Token过期时自动清理用户状态?
问题解答
1. Token过期时从状态移除用户
你可以在Token过期检查逻辑中触发Redux的登出action,同步清空用户状态和Cookie:
具体实现步骤:
- 编写Redux登出action与对应的reducer,负责清空用户信息并更新认证状态:
// redux/actions/authActions.js export const logout = () => (dispatch) => { // 清除Cookie中的Token document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; // 更新Redux状态 dispatch({ type: "LOGOUT", payload: null }); }; // redux/reducers/authReducer.js const initialState = { user: null, isAuthenticated: false }; export default function authReducer(state = initialState, action) { switch(action.type) { case "LOGOUT": return { ...state, user: null, isAuthenticated: false }; // 其他登录、获取用户详情的case逻辑... default: return state; } }
- 在请求拦截器(以Axios为例)中加入Token过期校验,一旦过期立即触发登出:
// utils/api.js import axios from "axios"; import { logout } from "../redux/actions/authActions"; import store from "../redux/store"; import jwtDecode from "jwt-decode"; const api = axios.create({ baseURL: process.env.NEXT_PUBLIC_STRAPI_URL }); api.interceptors.request.use(async (config) => { const token = document.cookie.split('; ').find(row => row.startsWith('token='))?.split('=')[1]; if (token) { const decoded = jwtDecode(token); // 校验Token是否过期(exp为时间戳,单位秒) if (decoded.exp * 1000 < Date.now()) { store.dispatch(logout()); window.location.href = '/login?expired=true'; } else { config.headers.Authorization = `Bearer ${token}`; } } return config; });
- 针对Next.js服务端渲染场景,在
getServerSideProps或Middleware中补充Token校验,避免服务端渲染过期用户信息:
// pages/protected-page.js export async function getServerSideProps(context) { const token = context.req.cookies.token; if (token) { const decoded = jwtDecode(token); if (decoded.exp * 1000 < Date.now()) { // 清除服务端Cookie context.res.setHeader('Set-Cookie', 'token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT'); return { redirect: { destination: '/login', permanent: false } }; } } // 其他服务端逻辑... return { props: {} }; }
2. 是否需要设置过期登出时间?
如果你的应用是敏感场景(如后台管理、支付系统),建议设置定时登出,既提升安全性也优化用户体验;普通业务场景可仅依赖每次请求的Token检查。
基于Next.js + Strapi实现定时登出:
登录时从Strapi返回的JWT中解析过期时间,计算剩余时长后设置定时器自动触发登出:
// 登录页面逻辑 import { useDispatch } from "react-redux"; import { loginSuccess } from "../redux/actions/authActions"; import { logout } from "../redux/actions/authActions"; import jwtDecode from "jwt-decode"; const LoginPage = () => { const dispatch = useDispatch(); const handleLogin = async (credentials) => { const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/auth/local`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }); const data = await res.json(); if (data.jwt) { const decoded = jwtDecode(data.jwt); const expiresIn = decoded.exp * 1000 - Date.now(); // 设置定时登出定时器 setTimeout(() => { dispatch(logout()); window.location.href = '/login?expired=true'; }, expiresIn); // 同步保存Token到Cookie和Redux document.cookie = `token=${data.jwt}; path=/; max-age=${expiresIn/1000}`; dispatch(loginSuccess(data.user)); } }; return <div>{/* 登录表单组件 */}</div>; };
注意:页面刷新后定时器会失效,需在全局布局组件中重新初始化定时器:
// components/Layout.js import { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { logout } from "../redux/actions/authActions"; import jwtDecode from "jwt-decode"; const Layout = ({ children }) => { const dispatch = useDispatch(); const { isAuthenticated } = useSelector(state => state.auth); useEffect(() => { if (isAuthenticated) { const token = document.cookie.split('; ').find(row => row.startsWith('token='))?.split('=')[1]; if (token) { const decoded = jwtDecode(token); const expiresIn = decoded.exp * 1000 - Date.now(); const timer = setTimeout(() => { dispatch(logout()); window.location.href = '/login?expired=true'; }, expiresIn); // 组件卸载时清除定时器 return () => clearTimeout(timer); } } }, [isAuthenticated, dispatch]); return <div>{children}</div>; };
3. 定时登出 vs 每次检查Token:哪种更合理?
建议两者结合:
- 每次请求检查Token:是核心安全保障,因为定时器可能因页面刷新、浏览器休眠、JS线程阻塞等失效,每次请求前验证Token能确保过期后不会发起无效请求,避免服务端返回401错误。
- 定时登出:是体验优化,能在Token过期前自动完成登出,避免用户操作到一半才触发过期提示,同时减少不必要的请求。
针对你现有逻辑,可保留每次请求的Token检查,同时添加定时登出逻辑,让两者互补。
内容的提问来源于stack exchange,提问作者Danny Coder
相关产品推荐
相关产品推荐

