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

能否基于用户角色在hapi-swagger中隐藏Swagger UI内指定API?

当然可以实现!hapi-swagger结合hapi的权限控制体系,完全能做到根据用户角色动态隐藏Swagger UI里的API。我结合你提到的/employee和/admin场景,给你详细讲下实现思路和代码示例:

核心实现思路
  1. 配置认证策略:先用hapi的认证插件(比如hapi-auth-jwt2)实现用户登录,让Swagger UI能识别用户角色。
  2. 路由权限标记:给每个API路由配置对应的角色权限要求(比如/admin只允许管理员访问)。
  3. 动态过滤文档:通过hapi-swagger的自定义documentation函数,根据当前登录用户的角色,过滤掉无权访问的路由,只返回用户能看的API文档。
完整代码示例

首先安装依赖:

npm install @hapi/hapi hapi-swagger @hapi/inert @hapi/vision hapi-auth-jwt2

然后是服务器代码:

const Hapi = require('@hapi/hapi');
const HapiSwagger = require('hapi-swagger');
const Inert = require('@hapi/inert');
const Vision = require('@hapi/vision');
const HapiAuthJWT = require('hapi-auth-jwt2');

const init = async () => {
  const server = Hapi.server({
    port: 3000,
    host: 'localhost'
  });

  // 注册JWT认证插件
  await server.register(HapiAuthJWT);

  // 配置JWT认证策略(实际项目请替换密钥和用户校验逻辑)
  server.auth.strategy('jwt', 'jwt', {
    key: 'your-strong-secret-key', // 换成你的加密密钥
    validate: async (decoded, request) => {
      // 模拟从数据库获取用户角色,真实场景请查库
      const userScope = decoded.role === 'admin' ? ['admin', 'employee'] : ['employee'];
      return { isValid: true, credentials: { role: decoded.role, scope: userScope } };
    },
    verifyOptions: { algorithms: ['HS256'] }
  });

  // 注册Swagger相关插件
  await server.register([
    Inert,
    Vision,
    {
      plugin: HapiSwagger,
      options: {
        info: {
          title: '角色控制的API文档',
          version: '1.0.0'
        },
        // 配置Swagger UI的认证入口
        securityDefinitions: {
          jwt: {
            type: 'apiKey',
            name: 'Authorization',
            in: 'header',
            scheme: 'bearer'
          }
        },
        // 全局启用JWT认证,用户需要先登录才能看文档
        security: [{ jwt: [] }],
        // 核心:动态过滤文档的逻辑
        documentation: async (server, request) => {
          // 获取原始的Swagger文档
          const rawDocs = await server.plugins['hapi-swagger'].getDocumentation();
          
          // 未登录用户返回空文档(可根据需求调整为公共API)
          if (!request.auth.isAuthenticated) {
            return { paths: {} };
          }

          const userRoles = request.auth.credentials.scope;
          const filteredPaths = {};

          // 遍历所有路由,判断用户是否有权限访问
          for (const path in rawDocs.paths) {
            const pathConfig = rawDocs.paths[path];
            let hasAccess = false;

            // 检查该路由下所有HTTP方法的权限配置
            for (const method in pathConfig) {
              const securityRules = pathConfig[method].security;
              if (securityRules) {
                // 获取路由要求的角色
                const requiredRoles = securityRules[0].jwt || [];
                // 判断用户是否拥有至少一个要求的角色
                hasAccess = requiredRoles.some(role => userRoles.includes(role));
              } else {
                // 没有配置权限的路由默认允许访问(可根据需求修改)
                hasAccess = true;
              }
              if (hasAccess) break;
            }

            if (hasAccess) {
              filteredPaths[path] = pathConfig;
            }
          }

          // 返回过滤后的文档
          rawDocs.paths = filteredPaths;
          return rawDocs;
        }
      }
    }
  ]);

  // 定义业务路由
  server.route([
    {
      method: 'GET',
      path: '/employee',
      handler: (request, h) => {
        return { message: '员工专属数据' };
      },
      options: {
        auth: {
          strategy: 'jwt',
          scope: ['employee', 'admin'] // 员工和管理员都能访问接口
        },
        plugins: {
          'hapi-swagger': {
            security: [{ jwt: ['employee'] }] // 标记该路由需要employee角色权限
          }
        },
        description: '员工API',
        tags: ['api', 'employee']
      }
    },
    {
      method: 'GET',
      path: '/admin',
      handler: (request, h) => {
        return { message: '管理员专属数据' };
      },
      options: {
        auth: {
          strategy: 'jwt',
          scope: ['admin'] // 仅管理员能访问接口
        },
        plugins: {
          'hapi-swagger': {
            security: [{ jwt: ['admin'] }] // 标记该路由需要admin角色权限
          }
        },
        description: '管理员API',
        tags: ['api', 'admin']
      }
    }
  ]);

  await server.start();
  console.log(`服务器运行在: ${server.info.uri}`);
};

process.on('unhandledRejection', (err) => {
  console.error(err);
  process.exit(1);
});

init();
关键细节说明
  1. 认证与角色获取:示例用JWT作为认证方式,你可以替换成hapi-auth-basic或其他适合的插件,只要能在validate函数中拿到用户角色即可。
  2. Swagger认证入口:Swagger UI顶部会出现“Authorize”按钮,用户输入JWT令牌(格式:Bearer <token>)后,后端就能识别用户角色。
  3. 测试方式:生成两个JWT令牌,一个role为admin,一个为employee,分别认证后就能看到对应的API列表——管理员能看到两个API,员工只能看到/employee。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:21:33