跳到主要内容

认证鉴权体系

问题

前端和服务端的认证鉴权方案有哪些?Session、JWT、OAuth、SSO 各有什么特点?

答案

认证方案全景

方案对比

维度Session-CookieJWTOAuth 2.0SSO
状态有状态(服务端存储)无状态(客户端存储)基于 Token基于 Token
存储服务端内存/Redis客户端客户端认证中心
扩展性需要共享 Session天然支持分布式天然支持天然支持
安全性CSRF 风险XSS 风险较安全较安全
适用场景传统 Web 应用SPA、移动端、API第三方登录多系统统一登录
session-example.ts
// 服务端(Express + express-session)
import session from 'express-session';
import RedisStore from 'connect-redis';

app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true, // 防 XSS
secure: true, // 仅 HTTPS
sameSite: 'lax', // 防 CSRF
maxAge: 24 * 60 * 60 * 1000, // 1 天
},
}));

// 登录
app.post('/login', (req, res) => {
// 验证用户名密码...
req.session.userId = user.id;
res.json({ success: true });
});

JWT

jwt-example.ts
import jwt from 'jsonwebtoken';

// 签发 Token
const generateTokens = (userId: string) => {
const accessToken = jwt.sign(
{ userId, type: 'access' },
process.env.JWT_SECRET!,
{ expiresIn: '15m' }
);

const refreshToken = jwt.sign(
{ userId, type: 'refresh' },
process.env.JWT_REFRESH_SECRET!,
{ expiresIn: '7d' }
);

return { accessToken, refreshToken };
};

// 验证中间件
const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'Unauthorized' });

try {
const payload = jwt.verify(token, process.env.JWT_SECRET!);
req.user = payload;
next();
} catch {
return res.status(401).json({ error: 'Token expired' });
}
};
JWT 注意事项
  • JWT 无法主动失效:一旦签发,在过期前一直有效。需要黑名单机制或短有效期 + RefreshToken
  • JWT 体积比 Session ID 大
  • 不要在 JWT 中存敏感信息(payload 只是 Base64 编码,不是加密)

OAuth 2.0 授权码流程


常见面试问题

答案

存储位置优点缺点
localStorage不会自动发送,无 CSRF 风险XSS 可窃取
Cookie (httpOnly)XSS 无法读取需防 CSRF

推荐httpOnly Cookie + SameSite=Lax,安全性最高。如果是纯 SPA + 跨域 API,用 localStorage + 短有效期也可接受。

Q2: Token 无感刷新怎么做?

答案

双 Token 机制:AccessToken(短期 15min)+ RefreshToken(长期 7d)。AccessToken 过期后,用 RefreshToken 换新的 AccessToken,用户无感知。

关键实现:Axios 拦截器中检测 401,自动用 RefreshToken 刷新,并重放失败的请求。

Q3: 如何实现退出登录让 JWT 失效?

答案

JWT 本身无法撤销,常用方案:

  1. Redis 黑名单:退出时将 token 加入黑名单,每次请求检查
  2. 版本号:用户表加 tokenVersion,退出时 +1,JWT 中携带版本号比对
  3. 短有效期:AccessToken 5-15 分钟,过期自然失效

Q4: Session 和 JWT 怎么选?

答案

  • Session:传统 SSR 应用、需要即时踢人、安全性要求高
  • JWT:SPA、移动端、微服务、需要跨域/跨服务认证

Q5: PKCE 是什么?为什么需要?

答案

PKCE(Proof Key for Code Exchange)解决公共客户端(SPA、移动端)OAuth 授权码被截获的风险:

  1. 客户端生成随机 code_verifier,计算 code_challenge = SHA256(code_verifier)
  2. 授权请求携带 code_challenge
  3. 换 Token 时携带 code_verifier,服务端验证匹配

即使授权码被截获,没有 code_verifier 也无法换取 Token。

相关链接