• 欢迎访问少将全栈,学会感恩,乐于付出,珍惜缘份,成就彼此、推荐使用最新版火狐浏览器和Chrome浏览器访问本网站。
  • 吐槽,投稿,删稿,交个朋友
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏少将全栈吧

AI应用认证方案选型:JWT、OAuth 2.0和Session的代码实现与对比

AI Coding 实测 admin 1小时前 6次浏览 已收录 扫描二维码

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应用的基础设施。选对方案,后面功能开发会顺很多。选错了,重构成本很高。建议在项目启动阶段就定好,不要先随便搞一个后面再换。

喜欢 (0)赏
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。