C# 未指定authenticationScheme,也未找到DefaultChallengeScheme-ASP.NET core 2.1
我正在使用ASP.NET Core 2.1 WebApi项目,因为我们使用了基于令牌的身份验证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
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,它被视为刷新令牌,并且只能用作刷新令牌。