繁体   English   中英

没有指定authenticationScheme,也没有找到DefaultChallengeScheme-ASP.NET Core 2.1

[英]No authenticationScheme was specified, and there was no DefaultChallengeScheme found - ASP.NET core 2.1

我正在使用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方法传递标题,则工作正常,但是缺少相同标题的标题给出错误No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

这里我有两个问题:

1)可以在未指定标头的情况下将500例外发送给用户端吗?

2)如何处理这种情况并传递有意义的消息“缺少标题”或其他内容?

可以在未指定标头的情况下将500带有此异常的内容发送到用户端吗?

恐怕不是一个好主意。

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

如何处理这种情况并传递有意义的消息“缺少标题”或其他内容?

首先,我不得不说我不认为使用AuthorizationFilter来验证用户身份不是一个好的选择。

如错误所述, 由于未指定AuthenticationScheme且未找到DefaultChallengeScheme而引发该错误

要修复该错误, 只需指定身份验证方案 例如,如果您使用的是JwtToken ,则应添加AddAuthentication(JwtBearerDefaults.AuthenticationScheme)或使用[Authorize(AuthenticationSchemes ="JwtBearerDefaults.AuthenticationScheme")]属性

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

public abstract class AuthenticationHandler<TOptions> : IAuthenticationHandler 
    where TOptions : AuthenticationSchemeOptions, new()
{
     // ...
}

由于默认的HandleChallengeAsync()将发送401响应,因此您可以简单地扩展AuthenticationHandler并覆盖HandleChallengeAsync()方法以自定义您自己的消息来挑战用户

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;
    }

}

最后,您还需要注册身份验证处理程序:

services.AddAuthentication("OurOwnAuthN")
        .AddScheme<OurOwnAuthNOpts,OurOwnAuthNHandler>("OurOwnAuthN","Our Own AuthN Scheme",opts=>{
            // ...
        });

如果您不想将“ OurOwnAuthN”设置为默认的身份验证方案,则可以使用[Authorize(AuthenticationSchemes ="OurOwnAuthN")]保护您的资源:

// your `ConfigureServices()`
services.AddAuthentication()
        .AddScheme<OurOwnAuthNOpts,OurOwnAuthNHandler>("OurOwnAuthN","Our Own AuthN Scheme",opts=>{
            // ...
        });


// your action method :
// GET api/values/5
[Authorize(AuthenticationSchemes ="OurOwnAuthN")]        
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
    return "value";
}

如果用户发送的请求没有令牌或令牌不正确,则服务器的响应将是:

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令牌,则可以使用以下代码注册JwtBearer身份验证:

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 提供了一个Challenge以自定义WWW-Authenticate

    .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
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

请注意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=>{
            // ...
     });

响应将是:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM