Аутентификация на основе токенов является предпочтительной. Однако, если вам нужна пользовательская схема ApiKeyAuth
, это возможно.
Во-первых, кажется, что Authorize("APIKeyAuth")
здесь не имеет смысла, так как мы должны аутентифицировать пользователя перед авторизацией. При поступлении входящего запроса сервер не знает, кто его использует. Итак, давайте переместим ApiKeyAuth
с Authorization
на Authentication
.
Для этого просто создайте пустышку ApiKeyAuthOpts
, которую можно использовать для хранения параметров
public class ApiKeyAuthOpts : AuthenticationSchemeOptions
{
}
и простой ApiKeyAuthHandler
для обработки аутентификации (я просто скопировал некоторые из ваших кодов выше)::
public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOpts>
{
public ApiKeyAuthHandler(IOptionsMonitor<ApiKeyAuthOpts> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
private const string API_TOKEN_PREFIX = "api-key";
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
string token = null;
string authorization = Request.Headers["Authorization"];
if (string.IsNullOrEmpty(authorization)) {
return AuthenticateResult.NoResult();
}
if (authorization.StartsWith(API_TOKEN_PREFIX, StringComparison.OrdinalIgnoreCase)) {
token = authorization.Substring(API_TOKEN_PREFIX.Length).Trim();
}
if (string.IsNullOrEmpty(token)) {
return AuthenticateResult.NoResult();
}
// does the token match ?
bool res =false;
using (DBContext db = new DBContext()) {
var login = db.Login.FirstOrDefault(l => l.Apikey == token); // query db
res = login ==null ? false : true ;
}
if (!res) {
return AuthenticateResult.Fail($"token {API_TOKEN_PREFIX} not match");
}
else {
var id=new ClaimsIdentity(
new Claim[] { new Claim("Key", token) }, // not safe , just as an example , should custom claims on your own
Scheme.Name
);
ClaimsPrincipal principal=new ClaimsPrincipal( id);
var ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
}
Наконец, нам все еще нужно немного настроек, чтобы заставить их работать:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthentication("ApiKeyAuth")
.AddScheme<ApiKeyAuthOpts,ApiKeyAuthHandler>("ApiKeyAuth","ApiKeyAuth",opts=>{ });
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// ...
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
}
При отправке запроса к действию метод защищен [Authorize]
:
GET https://localhost:44366/api/values/1 HTTP/1.1
Authorization: api-key xxx_yyy_zzz
ответ будет HTTP/1.1 200 OK
. Когда вы отправляете запрос без правильного ключа, ответ будет:
HTTP/1.1 401 Unauthorized
Server: Kestrel
X-SourceFiles: =?UTF-8?B?RDpccmVwb3J0XDIwMThcOVw5LTEyXFNPLkFwaUtleUF1dGhcQXBwXEFwcFxhcGlcdmFsdWVzXDE=?=
X-Powered-By: ASP.NET
Date: Wed, 12 Sep 2018 08:33:23 GMT
Content-Length: 0