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

.NET Core 2 MVC中同一Action的多路由与差异化权限配置问题

解决方案

要实现不同路由对应不同权限的需求,你可以通过自定义继承HttpGetAttribute并实现异步授权过滤器的方式来完成,这样既保留了HttpGet的路由功能,又能为每个路由独立配置权限验证。以下是具体实现步骤:

1. 自定义AuthGetAttribute属性

创建一个继承自HttpGetAttribute并实现IAsyncAuthorizationFilter的自定义属性,它会接收路由模板和所需角色,然后在请求匹配对应路由时执行权限验证:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq;
using System.Threading.Tasks;

public class AuthGetAttribute : HttpGetAttribute, IAsyncAuthorizationFilter
{
    // 保存当前路由所需的角色
    public string RequiredRole { get; }

    // 构造函数:接收路由模板和需要的角色
    public AuthGetAttribute(string template, string requiredRole) : base(template)
    {
        RequiredRole = requiredRole;
    }

    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        // 获取当前Action对应的控制器信息
        if (context.ActionDescriptor is not ControllerActionDescriptor controllerActionDescriptor)
        {
            return;
        }

        // 动态获取控制器的路由前缀(支持显式[Route]属性或默认控制器名称)
        string controllerRoutePrefix = string.Empty;
        var controllerRouteAttrs = controllerActionDescriptor.ControllerTypeInfo.GetCustomAttributes<RouteAttribute>();
        if (controllerRouteAttrs.Any())
        {
            controllerRoutePrefix = controllerRouteAttrs.First().Template;
        }
        else
        {
            controllerRoutePrefix = controllerActionDescriptor.ControllerName.ToLower();
        }

        // 构造当前属性对应的完整请求路径
        var expectedPath = $"/{controllerRoutePrefix}/{Template}".Replace("//", "/");
        var requestPath = context.HttpContext.Request.Path.Value?.TrimEnd('/') ?? string.Empty;

        // 如果当前请求路径不匹配该属性的路由,跳过验证(避免多个路由属性互相干扰)
        if (!requestPath.Equals(expectedPath, StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        var user = context.HttpContext.User;
        // 1. 检查用户是否已登录
        if (!user.Identity.IsAuthenticated)
        {
            context.Result = new ChallengeResult();
            return;
        }

        // 2. 使用ASP.NET Core授权系统验证用户是否拥有指定角色
        var authService = context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
        var authResult = await authService.AuthorizeAsync(
            user,
            null,
            new RolesAuthorizationRequirement(new[] { RequiredRole })
        );

        if (!authResult.Succeeded)
        {
            context.Result = new ForbidResult();
        }
    }
}

2. 在控制器中使用自定义属性

替换原来的HttpGet属性为AuthGet,每个属性对应一个路由和所需角色:

[Route("test")] // 可以显式指定控制器路由,或省略使用默认的"test"(控制器名称小写)
public class TestController : ControllerBase
{
    // 路由/test/test1 要求用户拥有role1角色
    [AuthGet("test1", "role1")]
    // 路由/test/test2 要求用户拥有role2角色
    [AuthGet("test2", "role2")]
    public async Task<IActionResult> Test()
    {
        // 执行你的业务逻辑
        return Ok("操作成功");
    }
}

关键逻辑说明

  • 路由匹配判断:每个AuthGet属性只会验证匹配自己路由的请求,避免多个属性之间的验证干扰(比如访问test1时不会触发test2的角色验证)。
  • 动态路由前缀:自动识别控制器的路由前缀(不管是显式配置的[Route]还是默认的控制器名称),保证路径匹配的准确性。
  • 授权验证:使用ASP.NET Core官方的IAuthorizationService进行角色验证,符合框架的设计规范,也方便后续扩展更复杂的授权规则。

注意事项

  • 确保你的项目已经配置了身份验证(比如JWT、Cookie认证),否则user.Identity.IsAuthenticated会始终为false。
  • 如果需要支持多角色(比如用户拥有role1或role2即可访问),可以修改RequiredRole为string[],并调整RolesAuthorizationRequirement的参数为角色数组。
  • 若路由包含参数(比如test/{id}),可以使用ASP.NET Core的RouteMatcher类来实现更精准的路由匹配,替代简单的字符串相等判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:29:31