能否基于用户角色在hapi-swagger中隐藏Swagger UI内指定API?
当然可以实现!hapi-swagger结合hapi的权限控制体系,完全能做到根据用户角色动态隐藏Swagger UI里的API。我结合你提到的/employee和/admin场景,给你详细讲下实现思路和代码示例:
核心实现思路
- 配置认证策略:先用hapi的认证插件(比如
hapi-auth-jwt2)实现用户登录,让Swagger UI能识别用户角色。 - 路由权限标记:给每个API路由配置对应的角色权限要求(比如
/admin只允许管理员访问)。 - 动态过滤文档:通过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();
关键细节说明
- 认证与角色获取:示例用JWT作为认证方式,你可以替换成
hapi-auth-basic或其他适合的插件,只要能在validate函数中拿到用户角色即可。 - Swagger认证入口:Swagger UI顶部会出现“Authorize”按钮,用户输入JWT令牌(格式:
Bearer <token>)后,后端就能识别用户角色。 - 测试方式:生成两个JWT令牌,一个
role为admin,一个为employee,分别认证后就能看到对应的API列表——管理员能看到两个API,员工只能看到/employee。
内容的提问来源于stack exchange,提问作者ppb
相关产品推荐
相关产品推荐

