You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

设计授权架构:多客户端资源隔离的高效实现方案咨询

优化客户端资源隔离的授权方案(Node.js/Express + PostgreSQL)

针对你遇到的多层关联权限校验效率低、扩展性差的问题,这里提供一套更优的实现思路,既能简化业务SQL,又能确保客户端数据隔离:

一、核心优化方向

  1. 扁平化数据库权限标识:给所有资源表(shows/seasons/episodes)直接添加client_id字段,避免多层关联查询
  2. 集中式授权校验:用Express中间件统一处理权限逻辑,业务代码只专注资源操作
  3. JWT信息增强:在Token中携带clientId(或结合缓存获取),减少授权时的用户信息查询

二、具体实现步骤

1. 调整数据库设计

给每个资源表添加client_id外键,同时用触发器自动维护该字段的一致性(避免手动插入错误):

-- 给shows表添加client_id(原本已有,作为基准)
ALTER TABLE shows ADD CONSTRAINT fk_shows_client FOREIGN KEY (client_id) REFERENCES clients(id);

-- 给seasons表添加client_id并创建触发器
ALTER TABLE seasons ADD COLUMN client_id INT;
ALTER TABLE seasons ADD CONSTRAINT fk_seasons_client FOREIGN KEY (client_id) REFERENCES clients(id);

CREATE OR REPLACE FUNCTION set_season_client_id()
RETURNS TRIGGER AS $$
BEGIN
  SELECT client_id INTO NEW.client_id FROM shows WHERE id = NEW.show_id;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_set_season_client_id
BEFORE INSERT ON seasons
FOR EACH ROW
EXECUTE FUNCTION set_season_client_id();

-- 给episodes表添加client_id并创建触发器
ALTER TABLE episodes ADD COLUMN client_id INT;
ALTER TABLE episodes ADD CONSTRAINT fk_episodes_client FOREIGN KEY (client_id) REFERENCES clients(id);

CREATE OR REPLACE FUNCTION set_episode_client_id()
RETURNS TRIGGER AS $$
BEGIN
  SELECT client_id INTO NEW.client_id FROM seasons WHERE id = NEW.season_id;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_set_episode_client_id
BEFORE INSERT ON episodes
FOR EACH ROW
EXECUTE FUNCTION set_episode_client_id();

这样所有资源的client_id会自动从上层关联资源继承,确保数据一致性。

2. 增强JWT内容

登录接口返回的JWT中,除了userId,额外加入clientId(如果用户的所属客户端可能变更,也可以在授权时从缓存/数据库查询):

// 登录生成JWT示例
import jwt from 'jsonwebtoken';

const generateToken = (user: { id: number; clientId: number }) => {
  return jwt.sign(
    { userId: user.id, clientId: user.clientId },
    process.env.JWT_SECRET!,
    { expiresIn: '24h' }
  );
};

3. 编写通用权限校验中间件

创建一个可复用的中间件,根据资源类型自动校验用户与资源的客户端归属:

import { Request, Response, NextFunction } from 'express';
import { pool } from './db'; // 你的PostgreSQL连接池

type ResourceType = 'show' | 'season' | 'episode';

export const checkResourcePermission = (resourceType: ResourceType) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    const resourceId = req.params.id;
    const { clientId } = req.user; // 假设JWT解析后挂载到req.user

    // 映射资源类型到数据库表名
    const tableMap = {
      show: 'shows',
      season: 'seasons',
      episode: 'episodes'
    };
    const tableName = tableMap[resourceType];

    try {
      // 查询资源所属客户端
      const result = await pool.query(
        `SELECT client_id FROM ${tableName} WHERE id = $1`,
        [resourceId]
      );

      if (result.rows.length === 0) {
        return res.status(404).json({ error: '资源不存在' });
      }

      // 校验客户端匹配
      if (result.rows[0].client_id !== clientId) {
        return res.status(403).json({ error: '无权限操作该资源' });
      }

      next();
    } catch (err) {
      console.error('权限校验失败:', err);
      return res.status(500).json({ error: '服务器内部错误' });
    }
  };
};

4. 业务路由与控制器简化

在路由中引入中间件,业务控制器只需执行纯资源操作SQL:

// 路由示例
import express from 'express';
import { checkResourcePermission } from './middlewares/permission';
import { updateEpisodeTime } from './controllers/episode';

const router = express.Router();

// 先校验权限,再执行更新
router.post('/episodes/:id', checkResourcePermission('episode'), updateEpisodeTime);
// 控制器示例
export const updateEpisodeTime = async (req: Request, res: Response) => {
  const episodeId = req.params.id;
  const { time } = req.body;

  try {
    // 无需权限条件,中间件已校验通过
    await pool.query(
      'UPDATE episodes SET time = $1 WHERE id = $2',
      [time, episodeId]
    );
    res.status(200).json({ message: '剧集时长更新成功' });
  } catch (err) {
    console.error('更新失败:', err);
    res.status(500).json({ error: '更新剧集时长失败' });
  }
};

三、扩展性说明

  • 若新增资源层级(比如季下新增“部分”):只需给新表添加client_id字段、创建对应的触发器,再在中间件的tableMap中新增映射即可,无需修改现有业务代码
  • 未来角色权限变更:可在中间件中扩展角色校验逻辑(比如从JWT或数据库获取用户角色,判断是否允许CRUD)

内容的提问来源于stack exchange,提问作者Danny Hobo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 10:36:59