OAuth认证实现技能 oauth-implementation

OAuth认证实现技能涉及OAuth 2.0和OpenID Connect协议的实现,用于安全认证和授权。关键词:OAuth、OpenID Connect、认证、授权、第三方集成、SSO、API访问、安全流程、身份验证。

身份认证 0 次安装 0 次浏览 更新于 3/7/2026

name: OAuth实现 description: OAuth 2.0和OpenID Connect认证与安全流程。用于第三方集成、SSO系统、基于令牌的API访问,或遇到授权码流程、PKCE、令牌刷新、范围管理错误。

OAuth实现

实现OAuth 2.0和OpenID Connect以进行安全认证。

OAuth 2.0流程

流程 用例
授权码 Web应用(最安全)
授权码 + PKCE SPA、移动应用
客户端凭证 服务间通信
刷新令牌 会话续期

授权码流程(Express)

const express = require('express');
const jwt = require('jsonwebtoken');

// 步骤1:重定向到授权
app.get('/auth/login', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  req.session.oauthState = state;

  const params = new URLSearchParams({
    client_id: process.env.CLIENT_ID,
    redirect_uri: process.env.REDIRECT_URI,
    response_type: 'code',
    scope: 'openid profile email',
    state
  });

  res.redirect(`${PROVIDER_URL}/authorize?${params}`);
});

// 步骤2:处理回调
app.get('/auth/callback', async (req, res) => {
  if (req.query.state !== req.session.oauthState) {
    return res.status(400).json({ error: 'Invalid state' });
  }

  const tokenResponse = await fetch(`${PROVIDER_URL}/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: req.query.code,
      redirect_uri: process.env.REDIRECT_URI,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET
    })
  });

  const tokens = await tokenResponse.json();
  // 安全存储令牌并创建会话
});

PKCE用于公共客户端

function generatePKCE() {
  const verifier = crypto.randomBytes(32).toString('base64url');
  const challenge = crypto
    .createHash('sha256')
    .update(verifier)
    .digest('base64url');
  return { verifier, challenge };
}

安全要求

  • 始终使用HTTPS
  • 严格验证重定向URI
  • 对公共客户端使用PKCE
  • 在HttpOnly cookie中存储令牌
  • 实现令牌轮换
  • 使用短期访问令牌(15分钟)

附加实现

参见references/python-java.md了解:

  • 使用Authlib OIDC提供程序的Python Flask
  • OpenID Connect发现和JWKS端点
  • Java Spring Security OAuth2服务器
  • 令牌内省和吊销

永远不要做

  • 在localStorage中存储令牌
  • 使用隐式流程
  • 跳过状态参数验证
  • 在前端暴露客户端密钥
  • 使用长期访问令牌