Skip to content
On this page

授权安全

授权安全涉及确定经过身份验证的用户可以访问哪些资源和执行哪些操作。本指南将详细介绍如何实现安全的授权机制。

授权模型

基于角色的访问控制 (RBAC)

javascript
// RBAC 实现
class RBAC {
  constructor() {
    this.roles = new Map(); // 角色定义
    this.permissions = new Map(); // 权限定义
    this.rolePermissions = new Map(); // 角色-权限映射
    this.userRoles = new Map(); // 用户-角色映射
  }
  
  // 定义角色
  defineRole(roleName, inheritsFrom = []) {
    this.roles.set(roleName, { inheritsFrom });
    if (!this.rolePermissions.has(roleName)) {
      this.rolePermissions.set(roleName, new Set());
    }
  }
  
  // 定义权限
  definePermission(permissionName, description = '') {
    this.permissions.set(permissionName, { description });
  }
  
  // 分配权限给角色
  assignPermissionToRole(permission, role) {
    if (!this.rolePermissions.has(role)) {
      this.rolePermissions.set(role, new Set());
    }
    this.rolePermissions.get(role).add(permission);
  }
  
  // 分配角色给用户
  assignRoleToUser(userId, role) {
    if (!this.userRoles.has(userId)) {
      this.userRoles.set(userId, new Set());
    }
    this.userRoles.get(userId).add(role);
  }
  
  // 检查用户权限
  hasPermission(userId, permission) {
    const userRoles = this.userRoles.get(userId);
    if (!userRoles) return false;
    
    for (const role of userRoles) {
      if (this.checkRolePermission(role, permission)) {
        return true;
      }
    }
    return false;
  }
  
  // 递归检查角色权限(包括继承)
  checkRolePermission(role, permission) {
    const rolePermissions = this.rolePermissions.get(role);
    if (!rolePermissions) return false;
    
    if (rolePermissions.has(permission)) {
      return true;
    }
    
    // 检查继承的角色
    const roleDefinition = this.roles.get(role);
    if (roleDefinition && roleDefinition.inheritsFrom) {
      for (const inheritedRole of roleDefinition.inheritsFrom) {
        if (this.checkRolePermission(inheritedRole, permission)) {
          return true;
        }
      }
    }
    
    return false;
  }
}

// 使用示例
const rbac = new RBAC();

// 定义权限
rbac.definePermission('user:read', 'Read user information');
rbac.definePermission('user:write', 'Write user information');
rbac.definePermission('admin:manage', 'Manage administration');

// 定义角色
rbac.defineRole('user');
rbac.defineRole('admin', ['user']); // admin 继承 user 权限

// 分配权限
rbac.assignPermissionToRole('user:read', 'user');
rbac.assignPermissionToRole('user:write', 'user');
rbac.assignPermissionToRole('admin:manage', 'admin');

// 分配角色给用户
rbac.assignRoleToUser('user123', 'user');
rbac.assignRoleToUser('admin456', 'admin');

// 检查权限
console.log(rbac.hasPermission('user123', 'user:read')); // true
console.log(rbac.hasPermission('user123', 'admin:manage')); // false
console.log(rbac.hasPermission('admin456', 'user:read')); // true (继承)

基于属性的访问控制 (ABAC)

javascript
// ABAC 实现
class ABAC {
  constructor() {
    this.policies = [];
  }
  
  // 添加策略
  addPolicy(policy) {
    this.policies.push(policy);
  }
  
  // 检查权限
  checkPermission(subject, action, resource, environment = {}) {
    for (const policy of this.policies) {
      if (this.evaluatePolicy(policy, subject, action, resource, environment)) {
        return policy.effect === 'allow';
      }
    }
    return false; // 默认拒绝
  }
  
  // 评估策略
  evaluatePolicy(policy, subject, action, resource, environment) {
    // 检查主体条件
    if (policy.subject && !this.matchCondition(policy.subject, subject)) {
      return false;
    }
    
    // 检查动作条件
    if (policy.action && !this.matchCondition(policy.action, action)) {
      return false;
    }
    
    // 检查资源条件
    if (policy.resource && !this.matchCondition(policy.resource, resource)) {
      return false;
    }
    
    // 检查环境条件
    if (policy.environment && !this.matchCondition(policy.environment, environment)) {
      return false;
    }
    
    return true;
  }
  
  // 匹配条件
  matchCondition(condition, value) {
    if (typeof condition === 'function') {
      return condition(value);
    }
    
    if (typeof condition === 'string') {
      return condition === value;
    }
    
    if (condition instanceof RegExp) {
      return condition.test(value);
    }
    
    if (Array.isArray(condition)) {
      return condition.includes(value);
    }
    
    if (typeof condition === 'object') {
      return this.matchObjectCondition(condition, value);
    }
    
    return false;
  }
  
  // 匹配对象条件
  matchObjectCondition(condition, value) {
    for (const [key, expectedValue] of Object.entries(condition)) {
      const actualValue = this.getObjectPath(value, key);
      if (!this.matchCondition(expectedValue, actualValue)) {
        return false;
      }
    }
    return true;
  }
  
  // 获取对象路径值
  getObjectPath(obj, path) {
    return path.split('.').reduce((current, key) => current?.[key], obj);
  }
}

// 使用示例
const abac = new ABAC();

// 添加策略:用户可以编辑自己的资料
abac.addPolicy({
  effect: 'allow',
  subject: (subject) => subject.type === 'user',
  action: 'edit',
  resource: (resource) => resource.type === 'profile',
  environment: (env) => env.subject.id === env.resource.ownerId
});

// 添加策略:管理员可以在工作时间内执行任何操作
abac.addPolicy({
  effect: 'allow',
  subject: { role: 'admin' },
  action: /.*/,
  resource: /.*/,
  environment: (env) => {
    const hour = new Date().getHours();
    return hour >= 9 && hour <= 17; // 工作时间 9-17 点
  }
});

授权中间件

Express 授权中间件

javascript
// 基于 RBAC 的授权中间件
const createAuthMiddleware = (rbacInstance) => {
  return (requiredPermission) => {
    return (req, res, next) => {
      if (!req.user) {
        return res.status(401).json({ error: 'Authentication required' });
      }
      
      if (!rbacInstance.hasPermission(req.user.id, requiredPermission)) {
        return res.status(403).json({ error: 'Insufficient permissions' });
      }
      
      next();
    };
  };
};

// 使用中间件
const requirePermission = createAuthMiddleware(rbac);

app.get('/api/admin/users', 
  authenticateToken, 
  requirePermission('admin:manage'), 
  (req, res) => {
    // 只有拥有 admin:manage 权限的用户才能访问
    res.json(users);
  }
);

// 基于 ABAC 的授权中间件
const createABACMiddleware = (abacInstance) => {
  return (action, getResource = null) => {
    return (req, res, next) => {
      if (!req.user) {
        return res.status(401).json({ error: 'Authentication required' });
      }
      
      const resource = getResource ? getResource(req) : { type: 'unknown' };
      const environment = { subject: req.user, resource, request: req };
      
      if (!abacInstance.checkPermission(req.user, action, resource, environment)) {
        return res.status(403).json({ error: 'Access denied' });
      }
      
      next();
    };
  };
};

资源级授权

细粒度访问控制

javascript
// 资源所有者检查
class ResourceAuthorization {
  // 检查用户是否为资源所有者
  static async isOwner(userId, resourceId, resourceType) {
    switch (resourceType) {
      case 'document':
        const doc = await db.documents.findById(resourceId);
        return doc && doc.ownerId === userId;
        
      case 'profile':
        const profile = await db.profiles.findById(resourceId);
        return profile && profile.userId === userId;
        
      default:
        return false;
    }
  }
  
  // 检查共享资源访问权限
  static async canAccessSharedResource(userId, resourceId, resourceType) {
    switch (resourceType) {
      case 'document':
        // 检查是否被共享给用户
        const share = await db.documentShares.findOne({
          where: {
            documentId: resourceId,
            $or: [
              { userId }, // 直接分享给用户
              { groupId: { $in: await this.getUserGroups(userId) } } // 分享给用户组
            ]
          }
        });
        return !!share;
        
      default:
        return false;
    }
  }
  
  // 获取用户组
  static async getUserGroups(userId) {
    const memberships = await db.groupMemberships.find({
      where: { userId }
    });
    return memberships.map(m => m.groupId);
  }
  
  // 综合访问检查
  static async canAccessResource(userId, resourceId, resourceType, action) {
    // 首先检查是否为所有者
    if (await this.isOwner(userId, resourceId, resourceType)) {
      return true;
    }
    
    // 然后检查共享权限
    if (await this.canAccessSharedResource(userId, resourceId, resourceType)) {
      return true;
    }
    
    // 检查基于角色的权限
    const rbac = new RBAC();
    if (rbac.hasPermission(userId, `${resourceType}:${action}`)) {
      return true;
    }
    
    return false;
  }
}

API 端点授权

RESTful API 授权

javascript
// API 授权服务
class APIAuthorization {
  constructor(rbac) {
    this.rbac = rbac;
  }
  
  // 检查端点访问权限
  async checkEndpointAccess(req, user) {
    const { method, route } = req;
    const action = this.getMethodAction(method);
    const resource = this.extractResource(route.path, req.params);
    
    // 构建权限字符串
    const permission = `${resource}:${action}`;
    
    return this.rbac.hasPermission(user.id, permission);
  }
  
  // 根据 HTTP 方法确定操作类型
  getMethodAction(method) {
    const actionMap = {
      GET: 'read',
      POST: 'create',
      PUT: 'update',
      PATCH: 'update',
      DELETE: 'delete'
    };
    
    return actionMap[method.toUpperCase()] || 'access';
  }
  
  // 从路由中提取资源类型
  extractResource(path, params) {
    // 从路径中提取资源类型,例如 /api/users/:id -> user
    const pathParts = path.split('/').filter(part => part.length > 0);
    const resource = pathParts[pathParts.length - 1] || pathParts[pathParts.length - 2];
    
    // 移除参数部分
    return resource.replace(/:.*$/, '').replace(/[{}]/g, '');
  }
}

// 使用示例
const apiAuth = new APIAuthorization(rbac);

app.use('/api', async (req, res, next) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Authentication required' });
  }
  
  const hasAccess = await apiAuth.checkEndpointAccess(req, req.user);
  if (!hasAccess) {
    return res.status(403).json({ error: 'Insufficient permissions' });
  }
  
  next();
});

数据库级授权

行级安全

javascript
// 数据库查询授权
class DatabaseAuthorization {
  // 构建安全的查询条件
  static buildAuthorizedQuery(userId, resourceType, action, baseQuery = {}) {
    let authorizedQuery = { ...baseQuery };
    
    switch (resourceType) {
      case 'document':
        // 用户只能访问自己的文档或被共享的文档
        authorizedQuery.$or = [
          { ownerId: userId },
          { sharedWith: userId },
          { 
            sharedWithGroups: { 
              $in: this.getUserGroupIds(userId) 
            } 
          }
        ];
        break;
        
      case 'profile':
        // 用户只能访问自己的资料或公开的资料
        authorizedQuery.$or = [
          { userId: userId },
          { privacy: 'public' }
        ];
        break;
        
      default:
        // 默认行为:只允许访问用户自己的资源
        authorizedQuery.userId = userId;
    }
    
    return authorizedQuery;
  }
  
  // 获取用户组 ID
  static async getUserGroupIds(userId) {
    const groups = await db.groups.find({
      where: { members: userId }
    });
    return groups.map(g => g.id);
  }
  
  // 安全的数据访问方法
  static async findAuthorized(userId, resourceType, query = {}) {
    const authorizedQuery = this.buildAuthorizedQuery(userId, resourceType, 'read', query);
    return await db[resourceType].find(authorizedQuery);
  }
  
  static async findOneAuthorized(userId, resourceType, id) {
    const authorizedQuery = this.buildAuthorizedQuery(userId, resourceType, 'read', { _id: id });
    return await db[resourceType].findOne(authorizedQuery);
  }
  
  static async updateAuthorized(userId, resourceType, id, updateData) {
    // 检查用户是否可以更新此资源
    const resource = await this.findOneAuthorized(userId, resourceType, id);
    if (!resource) {
      throw new Error('Access denied: Cannot update this resource');
    }
    
    // 执行更新
    return await db[resourceType].updateOne(
      { _id: id },
      { $set: updateData }
    );
  }
  
  static async deleteAuthorized(userId, resourceType, id) {
    // 检查用户是否可以删除此资源
    const resource = await this.findOneAuthorized(userId, resourceType, id);
    if (!resource) {
      throw new Error('Access denied: Cannot delete this resource');
    }
    
    // 执行删除
    return await db[resourceType].deleteOne({ _id: id });
  }
}

授权安全最佳实践

配置驱动的授权

javascript
// 配置驱动的权限系统
const permissionConfig = {
  roles: {
    user: {
      permissions: [
        'profile:read',
        'profile:update:own',
        'document:create',
        'document:read:own',
        'document:update:own',
        'document:delete:own'
      ]
    },
    premium: {
      inherits: ['user'],
      permissions: [
        'document:share',
        'document:collaborate',
        'storage:increase'
      ]
    },
    admin: {
      permissions: ['*:*'] // 所有权限
    }
  },
  resources: {
    profile: {
      ownerActions: ['read', 'update', 'delete'],
      publicActions: ['read']
    },
    document: {
      ownerActions: ['read', 'update', 'delete', 'share'],
      collaboratorActions: ['read', 'update'],
      publicActions: []
    }
  }
};

class ConfigBasedAuthorization {
  constructor(config) {
    this.config = config;
    this.rolePermissions = new Map();
    this.setupPermissions();
  }
  
  setupPermissions() {
    for (const [roleName, roleConfig] of Object.entries(this.config.roles)) {
      let permissions = new Set();
      
      // 添加继承的权限
      if (roleConfig.inherits) {
        for (const inheritedRole of roleConfig.inherits) {
          const inheritedPerms = this.rolePermissions.get(inheritedRole);
          if (inheritedPerms) {
            for (const perm of inheritedPerms) {
              permissions.add(perm);
            }
          }
        }
      }
      
      // 添加角色特定权限
      if (roleConfig.permissions) {
        for (const perm of roleConfig.permissions) {
          permissions.add(perm);
        }
      }
      
      this.rolePermissions.set(roleName, permissions);
    }
  }
  
  hasPermission(userId, roleId, permission) {
    const rolePerms = this.rolePermissions.get(roleId);
    if (!rolePerms) return false;
    
    // 检查具体权限或通配符权限
    return rolePerms.has(permission) || 
           rolePerms.has('*:*') || 
           rolePerms.has(`${permission.split(':')[0]}:*`);
  }
}

授权缓存

javascript
// 授权结果缓存
class AuthorizationCache {
  constructor(ttl = 300000) { // 5分钟 TTL
    this.cache = new Map();
    this.ttl = ttl;
  }
  
  async checkWithCache(userId, permission, checkFunction) {
    const cacheKey = `${userId}:${permission}`;
    const cached = this.cache.get(cacheKey);
    
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.result;
    }
    
    const result = await checkFunction(userId, permission);
    
    this.cache.set(cacheKey, {
      result,
      timestamp: Date.now()
    });
    
    return result;
  }
  
  invalidateUserCache(userId) {
    for (const [key] of this.cache) {
      if (key.startsWith(`${userId}:`)) {
        this.cache.delete(key);
      }
    }
  }
  
  clear() {
    this.cache.clear();
  }
}

// 使用缓存的授权检查
const authCache = new AuthorizationCache();

class CachedAuthorization {
  static async hasPermission(userId, permission) {
    return await authCache.checkWithCache(
      userId, 
      permission, 
      (uid, perm) => rbac.hasPermission(uid, perm)
    );
  }
}

授权安全检查清单

  • [ ] 实施最小权限原则
  • [ ] 使用基于角色的访问控制 (RBAC)
  • [ ] 实现细粒度资源访问控制
  • [ ] 验证所有用户操作的权限
  • [ ] 防止 IDOR(不安全的直接对象引用)
  • [ ] 实施行级安全
  • [ ] 使用授权缓存提高性能
  • [ ] 记录和监控授权决策
  • [ ] 定期审查权限分配
  • [ ] 实施权限继承和分组
  • [ ] 提供权限审计功能

通过实施这些授权安全措施,您可以确保用户只能访问他们有权访问的资源和功能。