C# 未指定authenticationScheme,也未找到DefaultChallengeScheme-ASP.NET core 2.1

C# 未指定authenticationScheme,也未找到DefaultChallengeScheme-ASP.NET core 2.1,c#,authorization,jwt,asp.net-core-webapi,asp.net-core-2.1,C#,Authorization,Jwt,Asp.net Core Webapi,Asp.net Core 2.1,我正在使用ASP.NET Core 2.1 WebApi项目,因为我们使用了基于令牌的身份验证 public class UserIdentityFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext context) { StringValues authorizationHeaders; if (!context.Htt

我正在使用ASP.NET Core 2.1 WebApi项目,因为我们使用了基于令牌的身份验证

public class UserIdentityFilter : IAuthorizationFilter
{    
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        StringValues authorizationHeaders;
        if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationHeaders))
            return;
        ...
        ...
    }   
}
并具有用于错误处理的中间件:

public async Task Invoke(HttpContext context, ILogger logger, IAppConfiguration appConfiguration)
{            
    try
    {
        await _next(context);
    }
    catch (Exception ex)
    {               
        await HandleExceptionAsync(context, ex, logger, appConfiguration);
    }
}  
如果我为authorize方法传递头,则工作正常,但是缺少相同的头会导致错误
未指定authenticationScheme,并且未找到DefaultChallengeScheme。

我有两个问题:

1) 当未指定标头时,是否可以向用户端发送带有此异常的500

2) 如何处理这个场景并传递有意义的消息“header丢失”或其他什么

当未指定标头时,是否可以向用户端发送带有此异常的500

恐怕这不是个好主意

500
状态代码表示存在服务器错误。当客户端发送没有令牌的请求时,告诉客户端“发生内部错误”是没有意义的。更好的方法是发送
401
来挑战用户,或者发送
403
来禁止

如何处理这个场景并传递有意义的消息“header丢失”或其他什么

首先,我必须说,我不认为使用
AuthorizationFilter
对用户进行身份验证是一个好的选择

正如错误描述的那样,抛出错误是因为没有指定
身份验证方案
,也没有找到
DefaultChallengeScheme

要修复此错误,只需指定一个身份验证方案。例如,如果您正在使用
JwtToken
,则应添加
AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
或使用
[授权(AuthenticationSchemes=“jwtbearderdefaults.AuthenticationScheme”)]
属性

否则,如果要自定义它对用户进行身份验证的方式(例如,自定义基于令牌的身份验证),则应创建新的令牌身份验证处理程序。已经有一个内置的抽象
AuthenticationHandler
类:

public abstract class AuthenticationHandler<TOptions> : IAuthenticationHandler 
    where TOptions : AuthenticationSchemeOptions, new()
{
     // ...
}
最后,还需要注册身份验证处理程序:

services.AddAuthentication("OurOwnAuthN")
        .AddScheme<OurOwnAuthNOpts,OurOwnAuthNHandler>("OurOwnAuthN","Our Own AuthN Scheme",opts=>{
            // ...
        });
如果用户发送的请求没有令牌或令牌不正确,服务器的响应将是:

HTTP/1.1 401 Unauthorized
Transfer-Encoding: chunked
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET

tell me your token
HTTP/1.1 401 Unauthorized
Server: Kestrel
WWW-Authenticate: tell me your token, error="invalid_token"
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET
Content-Length: 0
HTTP/1.1 401 Unauthorized
Transfer-Encoding: chunked
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET

tell me your token
[编辑]

如果您使用的是Jwt令牌,您可以使用以下代码注册JWTBear身份验证:

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

JwtBearer AuthenticationHandler提供了一个
挑战
来定制
WWW Authenticate

public class OurOwnAuthenticationHandler : AuthenticationHandler<ApiKeyAuthOpts>
{
    public OurOwnAuthenticationHandler(IOptionsMonitor<ApiKeyAuthOpts> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) 
        : base(options, logger, encoder, clock)
    {
    }


    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        StringValues authorizationHeaders;
        if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationHeaders))
             return AuthenticateResult.NoResult();
        // ... return AuthenticateResult.Fail(exceptionMessage);
        // ... return AuthenticateResult.Success(ticket)
    } 

    protected override Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        Response.StatusCode = 401;
        var message = "tell me your token";
        Response.Body.Write(Encoding.UTF8.GetBytes(message));
        return Task.CompletedTask;
    }

    protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
    {
        Response.StatusCode = 403;
        var message = "you have no rights";
        Response.Body.Write(Encoding.UTF8.GetBytes(message));
        return Task.CompletedTask;
    }

}
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
        };
        options.Challenge ="tell me your token";;
    })
答复如下:

HTTP/1.1 401 Unauthorized
Transfer-Encoding: chunked
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET

tell me your token
HTTP/1.1 401 Unauthorized
Server: Kestrel
WWW-Authenticate: tell me your token, error="invalid_token"
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET
Content-Length: 0
HTTP/1.1 401 Unauthorized
Transfer-Encoding: chunked
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcMTBcMThcU08uYXV0aGVudGljYXRpb25TY2hlbWUsIE5vIERlZmF1bHRDaGFsbGVuZ2VTY2hlbWVcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET

tell me your token
注意
WwW-Authenticate
标题

另一种方法是通过以下方式向前推进挑战

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
        };
        options.ForwardChallenge = "OurOwnAuthN";
    })
    .AddScheme<OurOwnAuthNOpts,OurOwnAuthNHandler>("OurOwnAuthN","Our Own Authentication Scheme",opts=>{
            // ...
     });

注册
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
并添加了
[Authorize(AuthenticationSchemes=JwtBearerDefaults.AuthenticationScheme)]
但是,获取错误的
“未注册任何身份验证处理程序。您是否忘记调用AddAuthentication()。添加[SomeAuthHandler](\“Bearer\”,…)?
@Div您不需要存储令牌。Jwt令牌存储在客户端,并在服务器上验证。只需创建一个新令牌并将其发送到客户端就可以了。@Div我不知道是否有标准的方法来实现这一点。但我曾经发布过accessToken(在2小时内过期)和refreshToken(在2.1小时内过期)同时。客户端使用refreshToken请求新令牌,将旧的accessToken和refreshToken替换为新的。@Div即使刷新令牌在某个时间过期,客户端也可以再次登录并获得新的accessToken和refreshToken。服务器不关心这一点。他们只是验证令牌。@Div对不起,我误解了你关于刷新令牌的问题。我以为你正在尝试保存accessToken。人们通常会将刷新令牌保存在某个位置。如果你不想保存刷新令牌,只需发布一个名为刷新令牌的新JwtToken,它被视为刷新令牌,并且只能用作刷新令牌。