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

ASP.NET MVC中带角色的Authorize特性跳转Access Denied问题排查

问题根本原因

你的问题出在中间件执行顺序错误,其次加角色声明的写法也有小瑕疵:

1. 核心问题:中间件顺序不符合执行逻辑

ASP.NET Core 中间件严格按照注册的先后顺序执行,你当前的中间件排列为:

app.UseAuthentication() → 读取认证信息构造HttpContext.User
app.UseAuthorization() → 执行[Authorize]特性的权限校验
app.UseAddClaimsFromDb() → 从数据库读取角色,添加到User的声明中

也就是说,[Authorize]校验跑的时候,你还没有把Admin角色加到用户的声明里,自然校验失败跳转到AccessDenied页。你后面写的测试代码、还有视图里的User.IsInRole都是授权校验完成、进入控制器/视图执行阶段才跑的,这时候自定义中间件已经执行完,角色已经加上,所以返回true。

2. 次要问题:声明添加方式不规范

你新建了一个空的ClaimsIdentity来存角色声明,这个新Identity没有绑定认证类型,部分场景下可能出现身份不被识别的问题。


修复方案

第一步:调整中间件顺序

把自定义加角色的中间件挪到UseAuthentication之后,UseAuthorization之前,保证授权校验之前,角色已经被添加到用户声明中:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // 省略其他前置中间件...
    app.UseRouting();

    app.UseAuthentication();
    // 先加自定义角色声明,再执行授权校验
    app.UseAddClaimsFromDb(); 
    app.UseAuthorization();

    // 省略后续中间件...
}

第二步:优化声明添加逻辑

直接把角色声明加到已经认证的主Identity上,不需要新建Identity:

public async Task InvokeAsync(HttpContext httpContext, EmpDBContext dBContext)
{
    var user = httpContext.User;
    if(user != null && user.Identity.IsAuthenticated)
    {
        string email = user.Identity.Name;
        UserDetail userDetail = await dBContext.UserDetails.FirstOrDefaultAsync(e => e.EmailId == email);
        string role = userDetail?.Role ?? "Employee";
        
        // 取当前已经过认证的Identity,直接添加角色声明
        var authenticatedIdentity = user.Identities.First(i => i.IsAuthenticated);
        authenticatedIdentity.AddClaim(new Claim(ClaimTypes.Role, role));
    }
    await next(httpContext);
}

修改完成后,[Authorize(Roles = "Admin")]和自定义Policy的校验都会正常生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 08:54:04