我正在使用ASP.NET Core 2.1 WebApi项目,因为我们使用了基于令牌的身份验证
public class UserIdentityFilter:IAuthorizationFilter{ public void OnAuthorization(…
没有指定标题时,可以向用户端发送带有此异常的500吗?
我担心这不是个好主意。
该 500 状态代码表示存在服务器错误。当客户端发送没有令牌的请求时,告诉客户端“发生内部错误”是没有意义的。更好的方法是发送 401 挑战用户或发送 403 禁止 。
500
401
403
如何处理这种情况并传递有意义的消息“标题丢失”或什么?
首先,我不得不说我不认为使用 AuthorizationFilter 验证用户是一个不错的选择。
AuthorizationFilter
如错误所述, 的 抛出错误是因为没有 AuthenticationScheme 被指定了,没有 DefaultChallengeScheme 发现 强> 。
AuthenticationScheme
DefaultChallengeScheme
要解决这个问题, 的 只需指定身份验证方案 强> 。例如,如果您正在使用 JwtToken ,你应该添加一个 AddAuthentication(JwtBearerDefaults.AuthenticationScheme) 或使用 [Authorize(AuthenticationSchemes ="JwtBearerDefaults.AuthenticationScheme")] 属性
JwtToken
AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
[Authorize(AuthenticationSchemes ="JwtBearerDefaults.AuthenticationScheme")]
否则,如果您想要自定义用户身份验证的方式(例如,自定义基于令牌的身份验证),则应创建新的令牌身份验证处理程序。已经有一个内置的摘要 AuthenticationHandler 课程:
AuthenticationHandler
public abstract class AuthenticationHandler<TOptions> : IAuthenticationHandler where TOptions : AuthenticationSchemeOptions, new() { // ... }
的 自默认 HandleChallengeAsync() 会发一个 401 回应,你可以简单地扩展 AuthenticationHandler 并覆盖 HandleChallengeAsync() 自定义您自己的消息以挑战用户的方法 强> :
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”设置为默认身份验证方案,则可以使用a [Authorize(AuthenticationSchemes ="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 Token,则可以使用以下代码注册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 强> :
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 标题。
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=>{ // ... });