首页
学习
活动
专区
圈层
工具
发布

Swagger / OpenAPI -根据授权级别不同的模型表示

Swagger/OpenAPI 中根据授权级别不同的模型表示

基础概念

Swagger/OpenAPI 是一种用于描述 RESTful API 的规范,它允许开发者定义 API 的结构、参数、响应模型等信息。在实际应用中,经常需要根据用户的授权级别返回不同的模型表示,例如管理员能看到更多字段,普通用户只能看到部分字段。

实现方式

1. 使用不同的 Schema 定义

在 OpenAPI 规范中,可以为不同权限级别定义不同的模型:

代码语言:txt
复制
components:
  schemas:
    UserBasic:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string
          
    UserAdmin:
      allOf:
        - $ref: '#/components/schemas/UserBasic'
        - type: object
          properties:
            createdAt:
              type: string
              format: date-time
            lastLogin:
              type: string
              format: date-time
            isActive:
              type: boolean

2. 使用 securitySchemes 和条件响应

结合安全定义和不同响应:

代码语言:txt
复制
paths:
  /users/{id}:
    get:
      summary: Get user by ID
      security:
        - adminAuth: []
        - userAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/UserAdmin'
                  - $ref: '#/components/schemas/UserBasic'
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Request limit per hour

3. 代码实现示例(Spring Boot)

代码语言:txt
复制
@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/{id}")
    public ResponseEntity<?> getUser(@PathVariable Long id, 
                                    @AuthenticationPrincipal UserDetails userDetails) {
        User user = userService.findById(id);
        
        if (hasAdminRole(userDetails)) {
            return ResponseEntity.ok(toAdminDto(user));
        } else {
            return ResponseEntity.ok(toBasicDto(user));
        }
    }
    
    private UserBasicDto toBasicDto(User user) {
        UserBasicDto dto = new UserBasicDto();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        return dto;
    }
    
    private UserAdminDto toAdminDto(User user) {
        UserAdminDto dto = new UserAdminDto();
        dto.setId(user.getId());
        dto.setUsername(user.getUsername());
        dto.setEmail(user.getEmail());
        dto.setCreatedAt(user.getCreatedAt());
        dto.setLastLogin(user.getLastLogin());
        dto.setActive(user.isActive());
        return dto;
    }
    
    private boolean hasAdminRole(UserDetails userDetails) {
        return userDetails.getAuthorities().stream()
                .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
    }
}

优势

  1. 安全性:确保敏感信息不会暴露给未授权的用户
  2. 灵活性:可以根据不同角色定制返回的数据结构
  3. 文档清晰:API 文档中明确展示了不同权限下的响应差异
  4. 性能优化:减少不必要的数据传输

应用场景

  1. 用户管理系统(普通用户 vs 管理员视图)
  2. 电子商务平台(买家 vs 卖家 vs 平台管理员视图)
  3. 内容管理系统(读者 vs 作者 vs 编辑视图)
  4. 医疗系统(患者 vs 医生 vs 医院管理员视图)

常见问题与解决方案

问题1:如何保持文档与实际实现同步?

解决方案

  • 使用代码生成工具(如 SpringDoc OpenAPI)自动从代码生成文档
  • 定期审查 API 文档
  • 编写测试验证不同权限下的响应

问题2:如何处理大量权限级别导致的模型爆炸?

解决方案

  • 使用继承和组合来复用模型定义
  • 考虑使用动态字段过滤而非完全不同的模型
  • 实现基于视图的序列化策略

问题3:如何测试不同权限级别的响应?

解决方案示例(使用 Spring Security Test):

代码语言:txt
复制
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;
    
    @Test
    @WithMockUser(roles = "USER")
    public void getUser_asUser_returnsBasicInfo() throws Exception {
        mockMvc.perform(get("/api/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.id").exists())
               .andExpect(jsonPath("$.username").exists())
               .andExpect(jsonPath("$.createdAt").doesNotExist());
    }
    
    @Test
    @WithMockUser(roles = "ADMIN")
    public void getUser_asAdmin_returnsFullInfo() throws Exception {
        mockMvc.perform(get("/api/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.id").exists())
               .andExpect(jsonPath("$.username").exists())
               .andExpect(jsonPath("$.createdAt").exists());
    }
}

通过合理设计 OpenAPI 规范和实现代码,可以有效地为不同授权级别提供不同的模型表示,既保证了安全性又提供了良好的开发者体验。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的文章

领券