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

ASP.NET Core Web API角色权限与菜单接口开发技术咨询

菜单接口与业务模块控制器开发方案

一、菜单接口开发(角色级菜单权限)

核心思路

基于现有Role-Permission关联关系,将菜单与权限绑定,通过用户所属角色过滤出可见菜单,最终返回树形结构供前端渲染。

1. 定义菜单与权限的关联规则

  • 在Permission表中新增PermissionType字段(枚举:Menu/Api),标记哪些权限对应菜单;
  • 每个菜单对应唯一的PermissionKey(如menu_center、menu_calendar),在RolePermission中为不同角色分配对应菜单权限。

2. 菜单数据模型(DTO)

public class MenuDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Path { get; set; }
    public int? ParentId { get; set; }
    public string Icon { get; set; }
    public List<MenuDto> Children { get; set; } = new List<MenuDto>();
}

3. 接口实现步骤

  • 从JWT Token解析当前用户ID,通过UserRole表获取用户所有角色ID;
  • 关联Role、RolePermission、Permission表,筛选出PermissionType=Menu的权限记录;
  • 将权限映射为菜单数据,组装成树形结构返回。

示例控制器代码:

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MenuController : ControllerBase
{
    private readonly AppDbContext _dbContext;

    public MenuController(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet("user-menus")]
    public async Task<IActionResult> GetUserMenus()
    {
        // 从Claims获取用户ID
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        if (string.IsNullOrEmpty(userId))
            return Unauthorized();

        // 获取用户所有角色对应的菜单权限
        var menuPermissions = await _dbContext.UserRoles
            .Where(ur => ur.UserId == int.Parse(userId))
            .Join(_dbContext.RolePermissions, ur => ur.RoleId, rp => rp.RoleId, (ur, rp) => rp.PermissionId)
            .Join(_dbContext.Permissions, pid => pid, p => p.Id, (pid, p) => p)
            .Where(p => p.PermissionType == PermissionType.Menu)
            .ToListAsync();

        // 映射为菜单DTO并组装树形结构
        var menus = MapToMenuDtos(menuPermissions);
        var treeMenus = BuildMenuTree(menus);

        return Ok(treeMenus);
    }

    // 辅助方法:权限转菜单DTO
    private List<MenuDto> MapToMenuDtos(List<Permission> permissions)
    {
        return permissions.Select(p => new MenuDto
        {
            Id = p.Id,
            Name = p.Name,
            Path = p.Key,
            ParentId = p.ParentId,
            Icon = p.Icon
        }).ToList();
    }

    // 辅助方法:构建树形菜单
    private List<MenuDto> BuildMenuTree(List<MenuDto> menus)
    {
        var rootMenus = menus.Where(m => m.ParentId == null).ToList();
        foreach (var root in rootMenus)
        {
            root.Children = menus.Where(m => m.ParentId == root.Id).ToList();
            BuildChildTree(root, menus);
        }
        return rootMenus;
    }

    private void BuildChildTree(MenuDto parent, List<MenuDto> allMenus)
    {
        foreach (var child in parent.Children)
        {
            child.Children = allMenus.Where(m => m.ParentId == child.Id).ToList();
            BuildChildTree(child, allMenus);
        }
    }
}

4. 权限验证增强

  • 接口添加[Authorize]特性,限制仅已登录用户访问;
  • 可自定义PermissionAuthorizeAttribute,进一步验证用户是否拥有对应菜单权限。

二、业务模块控制器(Center/Clinic/Tariff/Calendar)开发方案

1. 统一架构规范

每个业务模块独立创建控制器、服务层、DTO,遵循分层架构:

  • 控制器:处理HTTP请求/响应,调用服务层逻辑;
  • 服务层:封装业务逻辑,与数据访问层交互;
  • DTO:定义输入(CreateXXXDto)、输出(XXXDto)模型,避免直接暴露数据库实体。

2. 权限控制落地

  • 为每个业务接口定义专属权限(如center_read、clinic_create),在Permission表中添加记录;
  • 通过RolePermission为不同角色分配权限(如医生可访问calendar_read,秘书可访问clinic_read);
  • 在控制器方法上添加授权特性,示例:
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class ClinicController : ControllerBase
{
    private readonly IClinicService _clinicService;

    public ClinicController(IClinicService clinicService)
    {
        _clinicService = clinicService;
    }

    // 仅拥有clinic_read权限的角色可访问
    [HttpGet]
    [Authorize(Policy = "clinic_read")]
    public async Task<IActionResult> GetClinics()
    {
        var clinics = await _clinicService.GetAllClinicsAsync();
        return Ok(clinics);
    }

    // 仅拥有clinic_create权限的角色可访问
    [HttpPost]
    [Authorize(Policy = "clinic_create")]
    public async Task<IActionResult> CreateClinic([FromBody] CreateClinicDto dto)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);

        var clinicId = await _clinicService.CreateClinicAsync(dto);
        return CreatedAtAction(nameof(GetClinicById), new { id = clinicId }, null);
    }

    [HttpGet("{id}")]
    [Authorize(Policy = "clinic_read")]
    public async Task<IActionResult> GetClinicById(int id)
    {
        var clinic = await _clinicService.GetClinicByIdAsync(id);
        if (clinic == null)
            return NotFound();
        return Ok(clinic);
    }
}

3. 授权策略配置

在Program.cs中配置基于权限的授权策略:

builder.Services.AddAuthorization(options =>
{
    var permissions = builder.Configuration.GetSection("Permissions").Get<List<string>>();
    foreach (var perm in permissions)
    {
        options.AddPolicy(perm, policy =>
            policy.RequireClaim("Permission", perm));
    }
});

注:登录生成JWT Token时,需将用户拥有的所有PermissionKey添加到Claims中,格式为new Claim("Permission", permissionKey)。

4. 核心开发要点

  • 数据访问:用EF Core实现CRUD,添加事务处理保证数据一致性;
  • 异常处理:全局异常过滤器捕获异常,返回统一格式的错误响应;
  • 复用性:通用CRUD逻辑封装为BaseService/BaseController,减少重复代码;
  • 验证:用数据注解或FluentValidation做输入参数验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:47:48