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

ASP.NET Core Web API自定义授权策略失败返回500而非401问题

自定义AuthorizationPolicy验证失败返回500而非401的问题解决

问题场景

在ASP.NET Core中实现自定义AuthorizationPolicy,操作步骤如下:

  • 继承IAuthorizationRequirement创建TokenRequirement类
  • 编写对应的TokenHandler授权处理类
  • 在Program.cs中注册授权处理器与自定义策略
  • 在控制器上添加[Authorize(Policy = "Token")]特性

当前问题:Token验证通过时正常返回200状态码及数据,但验证失败时抛出500内部服务器错误,而非预期的401未授权状态码。


自定义授权相关代码

TokenRequirement类

public class TokenRequirement : IAuthorizationRequirement
{
}

TokenHandler类

public class TokenHandler : AuthorizationHandler<TokenRequirement>
{
    ITokenService tokenService;
    public TokenHandler(ITokenService tokenService)
    {
        this.tokenService = tokenService ?? throw new ArgumentNullException(nameof(tokenService));
    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenRequirement requirement)
    {
        if (context != null)
        {
            var httpContext = (DefaultHttpContext)context.Resource;

            if (httpContext != null)
            {
                if (string.IsNullOrEmpty(httpContext.Request.Headers["Authorization"]))
                    context.Fail();
                else
                {
                    string jwtToken = httpContext.Request.Headers["Authorization"].ToString();
                    JwtSecurityToken token = tokenService.DecryptToken(jwtToken);
                    var claims = token.Claims;

                    if (token.Claims.Where(c => c.Type == "role" && c.Value == @"XXXX Authentication1").Count() > 0)
                        context.Succeed(requirement);
                    else
                    {
                        context.Fail();
                    }
                }
            }
            else
                context.Fail();
        }
        return Task.CompletedTask;
    }
}

Program.cs注册代码

builder.Services.AddSingleton<IAuthorizationHandler, FileTransferWebAPI.TokenHandler>();
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Token", policy =>
        policy.Requirements.Add(new TokenRequirement()));
});

控制器特性

[Authorize(Policy ="Token")]
public class FileTransferController : ControllerBase

捕获的错误信息

System.ArgumentNullException: String reference not set to an instance of a String. (Parameter 's')
   at System.Text.Encoding.GetBytes(String s)
   at System.Text.UTF8Encoding.UTF8EncodingSealed.GetBytes(String s)
   at Program.<>c__DisplayClass0_0.<<Main>$>b__1(JwtBearerOptions o) in D:\Projects\FileTransferWebAPI\FileTransferWebAPI\Program.cs:line 35
   at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
   at Microsoft.Extensions.Options.OptionsCache`1.<>c__3`1.<GetOrAdd>b__3_0(String name, ValueTuple`2 arg)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd[TArg](TKey key, Func`3 valueFactory, TArg factoryArgument)
   at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd[TArg](String name, Func`3 createOptions, TArg factoryArgument)
   at Microsoft.Extensions.Options.OptionsMonitor`1.Get(String name)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.InitializeAsync(AuthenticationScheme scheme, HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationHandlerProvider.GetHandlerAsync(HttpContext context, String authenticationScheme)
   at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Accept: */*
Connection: keep-alive
Host: 127.0.0.1:6200
User-Agent: PostmanRuntime/7.30.0
Accept-Encoding: gzip, deflate, br
Authorization: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJZCI6ImFlNjk3OGZmLTY2YTktNGZiYi1hMTAzLThiMWQxNTg4YTc5MCIsInN1YiI6IkJFSUpFUkVMQ1xcQUhaQUgiLCJqdGkiOiI4OWE0M2Y2ZS1mNTNjLTQwZDMtYjBkNS00NzkwYjczNzc1YzgiLCJuYW1laWQiOiJTLTEtNS0yMS04MDk4OTM5NjMtMjkzMjIzMjQ1OC0xMjQzMDA3NzAzLTkzMzIiLCJ1bmlxdWVfbmFtZSI6IkJFSUpFUkVMQ1xcQUhaQUgiLCJyb2xlIjpbIkJFSUpFUkVMQ1xcRG9tYWluIFVzZXJzIiwiRXZlcnlvbmUiLCJCVUlMVElOXFxBZG1pbmlzdHJhdG9ycyIsIkJVSUxUSU5cXFBlcmZvcm1hbmNlIExvZyBVc2VycyIsIkJVSUxUSU5cXFVzZXJzIiwiTlQgQVVUSE9SSVRZXFxORVRXT1JLIiwiTlQgQVVUSE9SSVRZXFxBdXRoZW50aWNhdGVkIFVzZXJzIiwiTlQgQVVUSE9SSVRZXFxUaGlzIE9yZ2FuaXphdGlvbiIsIkJFSUpFUkVMQ1xcQkVfTGFzdHBhc3NfV2VicGx1Z2luX1VzZXJzIiwiQkVJSkVSRUxDXFxHbG9iYWwgSUZTIDMzMjAwIiwiQkVJSkVSRUxDXFxFTUVBX1BBX1ZQTl9GdWxsX0FjY2VzcyIsIkJFSUpFUkVMQ1xcR2xvYmFsIFRlY2huaXF1ZSIsIkJFSUpFUkVMQ1xcRU1FQV9DYXl6dV9FbmR1c2VycyIsIkJFSUpFUkVMQ1xcR2xvYmFsIFN1cHBvcnQiLCJCRUlKRVJFTENcXEdsb2JhbF9FTVNFM19MaWMiLCJCRUlKRVJFTENcXFNjcmF0Y2hfRHJpdmVfQWNjZXNzIiwiQkVJSkVSRUxDXFxHbG9iYWxfU0NDTV9SRF9VU0VSUyIsIkJFSUpFUkVMQ1xcR2xvYmFsX0Nsb3VkX0FjY2VzcyIsIkJFSUpFUkVMQ1xcUEFfVGVzdF9BbGwiLCJCRUlKRVJFTENcXEdsb2JhbF9BbGxfVXNlcnNfQ2xvdWQiLCJCRUlKRVJFTENcXEdsb2JhbCBSRCBBbGwiLCJCRUlKRVJFTENcXERlcHQgNzUgU1cgRGV2ZWxvcG1lbnQiLCJCRUlKRVJFTENcXEJFX0xhc3RwYXNzX1VzZXJzIiwiQkVJSkVSRUxDXFxHbG9iYWwgUkQgU0UiLCJCRUlKRVJFTENcXERlcHQgNzAgSE1JIEV4dHJhIFVzZXJzIiwiQkVJSkVSRUxDXFxHbG9iYWxfTzM2NV9BcHBzX0VYTyIsIkJFSUpFUkVMQ1xcR2xvYmFsIFImRCBITUkiLCJOVCBBVVRIT1JJVFlcXE5UTE0gQXV0aGVudGljYXRpb24iXSwibmJmIjoxNjczMjgwNTEwLCJleHAiOjE2NzMyODA4MTAsImlhdCI6MTY3MzI4MDUxMCwiaXNzIjoicGFuZWwiLCJhdWQiOiJ0cmFuc2ZlckNsaWVudCJ9.ONEXXnlb3dVGs0bcahCtD4EIvZoYMaYDVqV1XYabMRQVmoRMSeEUODtlhsZHOm0Nq2r6c3zBSy_g5j9bTyId-g
Postman-Token: d687b92f-0e65-45c8-a1ce-9d7c88d9dfd9

问题原因及解决方法

原因分析

从异常栈可以看出,错误发生在JwtBearerOptions配置的第35行:调用Encoding.GetBytes(String s)时传入了null值。这说明项目中同时配置了JWT Bearer认证,但相关密钥或参数未正确初始化,当授权失败触发Challenge操作时,JWT认证处理器尝试使用null值执行编码操作,最终导致500错误。

解决步骤

  1. 修复JWT认证配置
    打开Program.cs,找到AddJwtBearer的配置代码,确保所有必填参数(如TokenValidationParameters中的IssuerSigningKey)都已正确赋值,无null值。示例正确配置:

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = builder.Configuration["Jwt:Issuer"],
                ValidAudience = builder.Configuration["Jwt:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
            };
        });
    

    确保配置文件中存在Jwt:Key、Jwt:Issuer、Jwt:Audience的有效键值对。

  2. 自定义授权失败处理逻辑
    如果不需要JWT Bearer认证,可直接移除相关配置;或者自定义授权结果处理器,跳过默认Challenge流程,直接返回401:

    builder.Services.AddSingleton<IAuthorizationMiddlewareResultHandler, CustomAuthorizationMiddlewareResultHandler>();
    
    public class CustomAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
    {
        public async Task HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
        {
            if (!authorizeResult.Succeeded)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                return;
            }
            await next(context);
        }
    }
    
  3. 修正TokenHandler潜在问题

    • 避免强制转换context.Resource,改用类型检查:
      if (context.Resource is HttpContext httpContext)
      {
          // 处理逻辑
      }
      
    • 捕获tokenService.DecryptToken可能抛出的异常,避免未捕获异常导致500错误:
      try
      {
          string jwtToken = httpContext.Request.Headers["Authorization"].ToString();
          JwtSecurityToken token = tokenService.DecryptToken(jwtToken);
          // 角色验证逻辑
      }
      catch (Exception)
      {
          context.Fail();
      }
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 17:12:34