跳到主要内容

前端鉴权方案选型

场景

新项目需要设计用户登录和鉴权方案,如何选择合适的认证方式?

方案对比

主流鉴权方案

方案原理适用场景
Cookie + Session服务端存储会话,Cookie 携带 SessionID传统 Web、SSR
JWT(Token)无状态令牌,前端存储并携带SPA、微服务
OAuth 2.0第三方授权接入微信/GitHub 登录
SSO 单点登录统一认证中心多系统同账号

JWT 方案实现

auth-flow.ts
// 登录
async function login(email: string, password: string) {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password }),
credentials: 'include', // 携带 cookie
});
const data = await res.json();
// access_token 通常通过 Set-Cookie httpOnly 设置
// 或返回在 body 中由前端存储
return data;
}

// Axios 请求拦截器 — 自动附加 Token
axios.interceptors.request.use((config) => {
const token = getAccessToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});

// 响应拦截器 — 401 时刷新 Token
axios.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401 && !error.config._retry) {
error.config._retry = true;
await refreshToken();
return axios(error.config);
}
return Promise.reject(error);
}
);

路由权限控制

ProtectedRoute.tsx
import { Navigate, useLocation } from 'react-router-dom';

function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { isAuthenticated, isLoading } = useAuth();
const location = useLocation();

if (isLoading) return <Spinner />;

if (!isAuthenticated) {
return <Navigate to="/login" state={{ from: location }} replace />;
}

return <>{children}</>;
}

// 路由配置
const router = createBrowserRouter([
{ path: '/login', element: <LoginPage /> },
{
path: '/dashboard',
element: (
<ProtectedRoute>
<DashboardPage />
</ProtectedRoute>
),
},
]);

按钮级权限控制

Permission.tsx
function usePermission() {
const { user } = useAuth();
const permissions = user?.permissions ?? [];

return {
hasPermission: (code: string) => permissions.includes(code),
};
}

// 使用
function AdminPanel() {
const { hasPermission } = usePermission();

return (
<div>
{hasPermission('user:create') && <button>创建用户</button>}
{hasPermission('user:delete') && <button>删除用户</button>}
</div>
);
}

方案选型决策


常见面试问题

Q1: JWT 和 Session 各有什么优缺点?

答案

维度JWTSession
存储前端存储服务端存储
扩展性好(无状态)需要共享 Session
安全性需防 XSS 窃取需防 CSRF
注销难以即时失效删除 Session 即可
移动端友好Cookie 支持弱
跨域友好需额外配置

Q2: Token 过期了怎么办?如何实现无感刷新?

答案

核心方案:双 Token 机制

  1. Access Token:短期(15 分钟),用于接口鉴权
  2. Refresh Token:长期(7 天),用于刷新 Access Token

流程:Access Token 过期 → 响应拦截器拦截 401 → 用 Refresh Token 获取新 Access Token → 重发失败请求 → 对并发请求做队列排队,避免多次刷新。

详细实现见:Token 无感刷新

Q3: 前端路由权限和按钮权限怎么实现?

答案

  1. 路由权限:后端返回用户可访问的路由列表 → 前端动态生成路由表 → ProtectedRoute 组件守卫
  2. 按钮权限:后端返回权限码列表 → usePermission Hook 判断 → 条件渲染按钮
  3. 接口权限:不应只靠前端,后端必须做鉴权(前端权限只是 UX 优化)

相关链接