AI应用认证方案选型:JWT、OAuth 2.0和Session的代码实现与对比
做一个AI应用,用户认证这块怎么搞?很多人卡在这里。API写好了,前端搭好了,但认证方案选不对,后面安全问题一大堆。这篇把三种主流方案讲清楚,附带可以直接用的代码。
先说结论:没有最好的方案,只有最适合你场景的。JWT适合无状态分布式部署,OAuth 2.0适合接入第三方登录,Session适合传统单体应用。下面逐个拆解。
JWT方案:无状态认证的首选
JWT(JSON Web Token)的核心思路是把用户信息直接编码在token里,服务端不需要查数据库验证。RFC 7519定义了这个标准。对于AI应用来说,好处是每次API请求带上token就行,不用维护session存储。
原理很简单。用户登录后,服务端用密钥签发一个JWT,包含Header(算法类型)、Payload(用户信息+过期时间)和Signature(签名)。客户端把token放在Authorization头里,服务端验签就行。
下面是Node.js的实现代码:
// jwt-auth.js
const jwt = require('jsonwebtoken');
const SECRET_KEY = process.env.JWT_SECRET || 'your-secret-key';
// 签发token
function generateToken(user) {
return jwt.sign(
{ userId: user.id, email: user.email },
SECRET_KEY,
{ expiresIn: '24h', issuer: 'your-app' }
);
}
// 验证中间件
function authMiddleware(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, SECRET_KEY);
req.userId = decoded.userId;
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
// 路由使用
app.post('/api/chat', authMiddleware, async (req, res) => {
// req.userId 已验证,可以直接用
const result = await callAI(req.body.prompt);
res.json(result);
});
JWT有个关键问题要处理:token过期后怎么办?让用户重新登录体验差,所以一般配合refresh token。Access token有效期设短(15-30分钟),refresh token设长(7-30天)。access token过期后用refresh token换新的。
// refresh-token.js
function generateRefreshToken(user) {
return jwt.sign(
{ userId: user.id, type: 'refresh' },
SECRET_KEY,
{ expiresIn: '7d' }
);
}
app.post('/api/refresh', (req, res) => {
const refreshToken = req.body.refreshToken;
try {
const decoded = jwt.verify(refreshToken, SECRET_KEY);
if (decoded.type !== 'refresh') {
return res.status(401).json({ error: 'Invalid refresh token' });
}
const newAccessToken = generateToken({ id: decoded.userId });
res.json({ accessToken: newAccessToken });
} catch (err) {
return res.status(401).json({ error: 'Refresh token expired' });
}
});
JWT的缺点要注意:token签发后无法撤销(除非维护黑名单),用户信息变更不能实时生效。如果用户被ban了,token在过期前还能用。对于安全要求高的场景,这是个问题。
OAuth 2.0方案:接入第三方登录
让用户用Google、GitHub账号登录,用户体验好很多。OAuth 2.0是RFC 6749定义的标准协议。根据Google自己的统计,支持社交登录的网站注册转化率提升20%到40%。
原理是用户在第三方平台完成认证,第三方返回一个授权码,你的服务端用授权码换取access token,再用token获取用户信息。整个过程你的服务端不接触用户密码。
用Passport.js实现Google OAuth是最快的方式:
// oauth-setup.js
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
},
async (accessToken, refreshToken, profile, done) => {
// 在数据库里查找或创建用户
const user = await User.findOrCreate({
googleId: profile.id,
name: profile.displayName,
email: profile.emails[0].value
});
done(null, user);
}
));
// 路由
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile', 'email'] })
);
app.get('/auth/google/callback',
passport.authenticate('google', { session: false }),
(req, res) => {
// 认证成功,签发JWT
const token = generateToken(req.user);
res.redirect(`/callback?token=${token}`);
}
);
OAuth 2.0的坑主要在配置上。回调URL必须在Google Cloud Console里注册,开发环境和生产环境的回调地址不同,别忘了分别配置。还有scope权限范围,只申请需要的最小权限,不要一上来就要全部权限。
Session方案:传统但稳定
Session是最经典的认证方式。用户登录后,服务端创建一个session,把session ID存在cookie里。每次请求带cookie,服务端查session存储验证身份。
对于AI应用,Session方案适合单体部署、用户量不大的场景。好处是撤销方便,用户登出立刻生效。缺点是分布式部署需要共享session存储(比如Redis),增加了架构复杂度。
// session-auth.js
const session = require('express-session');
const RedisStore = require('connect-redis');
app.use(session({
store: new RedisStore({ url: process.env.REDIS_URL }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000 // 24小时
}
}));
// 登录
app.post('/api/login', async (req, res) => {
const { email, password } = req.body;
const user = await User.verify(email, password);
if (user) {
req.session.userId = user.id;
res.json({ success: true });
} else {
res.status(401).json({ error: 'Invalid credentials' });
}
});
// 认证中间件
function requireAuth(req, res, next) {
if (!req.session.userId) {
return res.status(401).json({ error: 'Please login' });
}
next();
}
三种方案怎么选
给一个决策框架:
如果你的AI应用是API-first的(比如提供LLM API服务),选JWT。无状态,扩展性好,客户端调用方便。
如果你的应用面向C端用户,想降低注册门槛,JWT + OAuth 2.0组合使用。用户用社交账号登录,登录后签发JWT。
如果你做的是内部工具或者用户量不大的SaaS,Session方案最省心。安全性好控制,实现也简单。
性能方面,JWT验签大概0.1-0.5毫秒,Session查询Redis大概0.5-2毫秒,差异不大。真正影响性能的是token大小和传输开销,JWT一般几百字节,Session cookie就几十字节。
安全方面,无论选哪个方案,几个底线要做到:HTTPS强制开启,token/cookie设置httpOnly和secure标志,密码用bcrypt存储(不要用MD5或SHA256直接hash),定期轮换密钥。OWASP的Authentication Cheat Sheet有完整的安全清单,建议照着检查一遍。
实际部署的几个建议
第一,不要自己实现认证系统。用成熟的库和框架,Passport.js、NextAuth、Lucia这些。认证系统的安全漏洞往往是细节问题,自己写容易踩坑。
第二,密钥管理。JWT的密钥不要硬编码在代码里,用环境变量或者密钥管理服务。密钥泄露等于所有token都可伪造。
第三,监控异常。同一用户短时间内大量token请求可能是token被窃取,IP短时间内大量登录失败可能是暴力破解。加一个简单的频率限制就能挡住大部分攻击。
认证是AI应用的基础设施。选对方案,后面功能开发会顺很多。选错了,重构成本很高。建议在项目启动阶段就定好,不要先随便搞一个后面再换。
