Skip to content

认证和授权源代码导览

JWT 源代码分析

jsonwebtoken 核心组件

jsonwebtoken 的源代码结构如下:

jsonwebtoken/
├── lib/
│   ├── index.js           # 主入口
│   ├── sign.js           # 签名功能
│   ├── verify.js         # 验证功能
│   ├── decode.js         # 解码功能
│   └── utils.js         # 工具函数
├── test/               # 测试文件
└── package.json

JWT 签名

javascript
// sign.js 核心逻辑
function sign(payload, secretOrPrivateKey, options) {
  // 默认选项
  const opts = {
    algorithm: 'HS256',
    expiresIn: '1h',
    ...options
  };

  // 创建头部
  const header = {
    alg: opts.algorithm,
    typ: 'JWT'
  };

  // 编码头部和载荷
  const encodedHeader = base64UrlEncode(JSON.stringify(header));
  const encodedPayload = base64UrlEncode(JSON.stringify(payload));

  // 创建签名数据
  const data = `${encodedHeader}.${encodedPayload}`;

  // 生成签名
  let signature;
  if (opts.algorithm.startsWith('HS')) {
    // HMAC 签名
    const crypto = require('crypto');
    const hmac = crypto.createHmac(
      opts.algorithm.replace('HS', 'SHA'),
      secretOrPrivateKey
    );
    hmac.update(data);
    signature = base64UrlEncode(hmac.digest('base64'));
  } else if (opts.algorithm.startsWith('RS')) {
    // RSA 签名
    const sign = crypto.createSign(opts.algorithm.replace('RS', 'SHA'));
    sign.update(data);
    signature = base64UrlEncode(sign.sign(secretOrPrivateKey, 'base64'));
  }

  // 返回完整的 JWT
  return `${data}.${signature}`;
}

// Base64 URL 编码
function base64UrlEncode(str) {
  return Buffer.from(str)
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

JWT 验证

javascript
// verify.js 核心逻辑
function verify(token, secretOrPublicKey, options) {
  // 分割 JWT
  const parts = token.split('.');
  if (parts.length !== 3) {
    throw new Error('Invalid token format');
  }

  const [encodedHeader, encodedPayload, signature] = parts;

  // 解码头部和载荷
  const header = JSON.parse(base64UrlDecode(encodedHeader));
  const payload = JSON.parse(base64UrlDecode(encodedPayload));

  // 验证算法
  const opts = { algorithms: ['HS256', 'RS256'], ...options };
  if (!opts.algorithms.includes(header.alg)) {
    throw new Error('Invalid algorithm');
  }

  // 验证签名
  const data = `${encodedHeader}.${encodedPayload}`;
  let isValid = false;

  if (header.alg.startsWith('HS')) {
    // HMAC 验证
    const crypto = require('crypto');
    const hmac = crypto.createHmac(
      header.alg.replace('HS', 'SHA'),
      secretOrPublicKey
    );
    hmac.update(data);
    const expectedSignature = base64UrlEncode(hmac.digest('base64'));
    isValid = crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  } else if (header.alg.startsWith('RS')) {
    // RSA 验证
    const verify = crypto.createVerify(header.alg.replace('RS', 'SHA'));
    verify.update(data);
    isValid = verify.verify(secretOrPublicKey, signature, 'base64');
  }

  if (!isValid) {
    throw new Error('Invalid signature');
  }

  // 验证过期时间
  if (payload.exp && Date.now() >= payload.exp * 1000) {
    throw new Error('Token expired');
  }

  // 验证签发时间
  if (payload.nbf && Date.now() < payload.nbf * 1000) {
    throw new Error('Token not yet valid');
  }

  // 验证签发者
  if (opts.issuer && payload.iss !== opts.issuer) {
    throw new Error('Invalid issuer');
  }

  // 验证受众
  if (opts.audience && payload.aud !== opts.audience) {
    throw new Error('Invalid audience');
  }

  return payload;
}

// Base64 URL 解码
function base64UrlDecode(str) {
  // 添加填充
  let padded = str;
  while (padded.length % 4) {
    padded += '=';
  }

  // 替换字符
  const base64 = padded
    .replace(/-/g, '+')
    .replace(/_/g, '/');

  return Buffer.from(base64, 'base64').toString();
}

OAuth 2.0 源代码分析

oauth2-server 核心组件

oauth2-server 的源代码结构如下:

oauth2-server/
├── lib/
│   ├── models/
│   │   ├── access-token.js    # 访问令牌模型
│   │   ├── refresh-token.js   # 刷新令牌模型
│   │   ├── client.js         # 客户端模型
│   │   └── user.js          # 用户模型
│   ├── grants/
│   │   ├── authorization-code.js # 授权码模式
│   │   ├── password.js      # 密码模式
│   │   ├── client-credentials.js # 客户端凭证模式
│   │   └── refresh-token.js # 刷新令牌模式
│   ├── handlers/
│   │   ├── authorize.js     # 授权处理器
│   │   ├── token.js         # 令牌处理器
│   │   └── authenticate.js  # 认证处理器
│   └── utils.js           # 工具函数
├── test/               # 测试文件
└── package.json

授权码模式

javascript
// grants/authorization-code.js 核心逻辑
class AuthorizationCodeGrant {
  constructor(model) {
    this.model = model;
  }

  // 处理授权请求
  async handleAuthorizationRequest(req) {
    // 验证客户端
    const client = await this.model.getClient(
      req.body.client_id,
      req.body.client_secret
    );
    if (!client) {
      throw new Error('Invalid client');
    }

    // 验证用户
    const user = await this.model.getUser(
      req.body.username,
      req.body.password
    );
    if (!user) {
      throw new Error('Invalid user');
    }

    // 验证重定向 URI
    if (!this.validateRedirectUri(client, req.body.redirect_uri)) {
      throw new Error('Invalid redirect URI');
    }

    // 验证权限范围
    const scope = this.validateScope(req.body.scope, client.scopes);
    if (!scope) {
      throw new Error('Invalid scope');
    }

    // 生成授权码
    const authorizationCode = await this.model.saveAuthorizationCode({
      code: this.generateAuthorizationCode(),
      client_id: client.id,
      user_id: user.id,
      redirect_uri: req.body.redirect_uri,
      scope: scope,
      expires_at: this.getExpirationDate(10 * 60) // 10 分钟
    });

    // 返回授权码
    return {
      code: authorizationCode.code,
      state: req.body.state
    };
  }

  // 处理令牌请求
  async handleTokenRequest(req) {
    // 验证客户端
    const client = await this.model.getClient(
      req.body.client_id,
      req.body.client_secret
    );
    if (!client) {
      throw new Error('Invalid client');
    }

    // 验证授权码
    const authCode = await this.model.getAuthorizationCode(req.body.code);
    if (!authCode) {
      throw new Error('Invalid authorization code');
    }

    // 验证授权码是否过期
    if (authCode.expires_at < Date.now()) {
      throw new Error('Authorization code expired');
    }

    // 验证重定向 URI
    if (authCode.redirect_uri !== req.body.redirect_uri) {
      throw new Error('Redirect URI mismatch');
    }

    // 验证客户端 ID
    if (authCode.client_id !== client.id) {
      throw new Error('Client ID mismatch');
    }

    // 生成访问令牌
    const accessToken = this.generateToken({
      sub: authCode.user_id,
      client_id: client.id,
      scope: authCode.scope
    });

    // 生成刷新令牌
    const refreshToken = this.generateToken({
      sub: authCode.user_id,
      client_id: client.id,
      scope: authCode.scope
    });

    // 保存令牌
    await this.model.saveToken({
      access_token: accessToken,
      refresh_token: refreshToken,
      client_id: client.id,
      user_id: authCode.user_id,
      scope: authCode.scope,
      expires_at: this.getExpirationDate(3600) // 1 小时
    });

    // 删除授权码
    await this.model.revokeAuthorizationCode(authCode.code);

    // 返回令牌
    return {
      access_token: accessToken,
      refresh_token: refreshToken,
      token_type: 'Bearer',
      expires_in: 3600,
      scope: authCode.scope
    };
  }

  // 生成授权码
  generateAuthorizationCode() {
    const crypto = require('crypto');
    return crypto.randomBytes(32).toString('base64');
  }

  // 生成令牌
  generateToken(payload) {
    const jwt = require('jsonwebtoken');
    return jwt.sign(payload, process.env.JWT_SECRET, {
      expiresIn: '1h'
    });
  }

  // 获取过期时间
  getExpirationDate(seconds) {
    return new Date(Date.now() + seconds * 1000);
  }

  // 验证重定向 URI
  validateRedirectUri(client, redirectUri) {
    return client.redirect_uris.includes(redirectUri);
  }

  // 验证权限范围
  validateScope(requestedScope, allowedScopes) {
    const requested = requestedScope ? requestedScope.split(' ') : [];
    return requested.filter(scope => allowedScopes.includes(scope)).join(' ');
  }
}

认证中间件源代码

JWT 中间件

javascript
// middleware/jwt.js 核心逻辑
function jwtMiddleware(options = {}) {
  return function (req, res, next) {
    // 提取令牌
    let token = null;

    // 从 Authorization 头提取
    const authHeader = req.headers.authorization;
    if (authHeader && authHeader.startsWith('Bearer ')) {
      token = authHeader.substring(7);
    }

    // 从 Cookie 提取
    if (!token && req.cookies && req.cookies.token) {
      token = req.cookies.token;
    }

    // 从查询参数提取
    if (!token && req.query.token) {
      token = req.query.token;
    }

    // 没有令牌
    if (!token) {
      return res.status(401).json({
        error: 'Unauthorized',
        message: 'No token provided'
      });
    }

    try {
      // 验证令牌
      const jwt = require('jsonwebtoken');
      const decoded = jwt.verify(token, options.secret || process.env.JWT_SECRET);

      // 附加用户信息到请求
      req.user = decoded;
      req.token = token;

      next();
    } catch (err) {
      // 令牌无效或过期
      return res.status(401).json({
        error: 'Unauthorized',
        message: err.message
      });
    }
  };
}

权限中间件

javascript
// middleware/permission.js 核心逻辑
function permissionMiddleware(requiredPermission) {
  return async function (req, res, next) {
    // 检查用户是否认证
    if (!req.user) {
      return res.status(401).json({
        error: 'Unauthorized',
        message: 'Authentication required'
      });
    }

    // 查询用户权限
    const userPermissions = await getUserPermissions(req.user.id);

    // 检查是否有所需权限
    if (!userPermissions.includes(requiredPermission)) {
      return res.status(403).json({
        error: 'Forbidden',
        message: 'Insufficient permissions'
      });
    }

    next();
  };

  // 获取用户权限
  async function getUserPermissions(userId) {
    // 从数据库查询用户权限
    const { User } = require('../models/user');
    const user = await User.findById(userId).populate('role');
    return user.role.permissions;
  }
}

密码哈希源代码

bcrypt 实现

javascript
// utils/password.js 核心逻辑
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 10;

// 哈希密码
async function hashPassword(password) {
  const salt = await bcrypt.genSalt(SALT_ROUNDS);
  const hash = await bcrypt.hash(password, salt);
  return hash;
}

// 验证密码
async function verifyPassword(password, hash) {
  const isValid = await bcrypt.compare(password, hash);
  return isValid;
}

// 生成随机密码
function generateRandomPassword(length = 12) {
  const crypto = require('crypto');
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
  let password = '';
  
  for (let i = 0; i < length; i++) {
    const randomIndex = crypto.randomInt(0, chars.length);
    password += chars[randomIndex];
  }
  
  return password;
}

module.exports = {
  hashPassword,
  verifyPassword,
  generateRandomPassword
};

总结

JWT 和 OAuth 2.0 的源代码展示了不同的认证授权机制。JWT 使用签名和验证机制,提供了无状态的认证方案;OAuth 2.0 使用授权码和令牌交换机制,提供了安全的第三方授权方案。理解两种方案的源代码结构,有助于我们更好地实现和扩展认证授权功能。