.NET Core 2.0 API:
Сначала я попытался использовать IAuthorizationPolicyProvider
, чтобы иметь динамические политики:
public class MyAuthorizationPolicyProvider: IAuthorizationPolicyProvider
{
internal const string PolicyPrefix = "MyJwt";
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if(!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return Task.FromResult<AuthorizationPolicy>((AuthorizationPolicy)null);
var authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
authorizationPolicyBuilder.AddRequirements((IAuthorizationRequirement)new MyAuthorizationRequirement(policyName.Substring(PolicyPrefix.Length)));
return Task.FromResult<AuthorizationPolicy>(authorizationPolicyBuilder.Build());
}
}
public class MyAuthorizationHandler: AuthorizationHandler<MyAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyAuthorizationRequirement requirement)
{
if(!context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
if(SomeLibrary.IsContextValid(context, requirement))
context.Succeed((IAuthorizationRequirement)requirement);
else
context.Fail();
return Task.CompletedTask;
}
}
и добавить аутентификацию:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
});
services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, MyAuthorizationPolicyProvider>();
И мой атрибут авторизации:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
internal const string PolicyPrefix = "MyJwt";
public MyAuthorizeAttribute(string permission)
{
this.Permission = permission;
}
public string Permission
{
get
{
if(this.Policy.Length < PolicyPrefix.Length)
return (string)null;
return this.Policy.Substring(PolicyPrefix.Length);
}
set
{
this.Policy = PolicyPrefix + value;
}
}
}
И я использовал: [MyAuthorize("anythings")]
Пока все было хорошо. Теперь мне нужно добавить новую аутентификацию (я имею в виду, что оба работают вместе).
Поэтому я изменил MyAuthorizationPolicyProvider
для поддержки новых политик:
public class MyAuthorizationPolicyProvider: IAuthorizationPolicyProvider
{
internal const string PolicyPrefix = "MyJwt";
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
{
return Task.FromResult<AuthorizationPolicy>(new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build());
}
public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
if(policyName == "newpolicy") //here
return AddNewPolicy();
if(!policyName.StartsWith(PolicyPrefix, StringComparison.OrdinalIgnoreCase))
return Task.FromResult<AuthorizationPolicy>((AuthorizationPolicy)null);
var authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
authorizationPolicyBuilder.AddRequirements((IAuthorizationRequirement)new MyAuthorizationRequirement(policyName.Substring(PolicyPrefix.Length)));
return Task.FromResult<AuthorizationPolicy>(authorizationPolicyBuilder.Build());
}
}
И изменить Добавить аутентификацию:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
})
.AddJwtBearer("newSchema", options =>
{
options.TokenValidationParameters = GetNewSchemaTokenValidationParameters();
});
services.AddSingleton<IAuthorizationHandler, MyAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, MyNewAuthorizationHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, MyAuthorizationPolicyProvider>();
А MyNewAuthorizationHandler
- это:
public class MyNewAuthorizationHandler: AuthorizationHandler<MyNewAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyNewAuthorizationRequirement requirement)
{
if(!context.User.Identity.IsAuthenticated)
{
context.Fail();
return Task.CompletedTask;
}
if(SomeNewLibrary.IsContextValid(context, requirement))
context.Succeed((IAuthorizationRequirement)requirement);
else
context.Fail();
return Task.CompletedTask;
}
}
а я пользуюсь [Authorize(Policy = "newpolicy")]
Теперь Первая проверка подлинности работает нормально с MyAuthorizationHandler
, но вторая проверка подлинности не удалась в MyNewAuthorizationHandler
, поскольку пользователь не прошел проверку подлинности и возврат этой строки завершился неудачно: if(!context.User.Identity.IsAuthenticated)
Что я пропустил?
Как я могу иметь множественную аутентификацию и в то же время использовать IAuthorizationPolicyProvider
для динамического добавления политик?
Я знаю, если я изменю AddAuthentication на:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "newSchema"; //here
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = GetTokenValidationParameters();
})
.AddJwtBearer("newSchema", options =>
{
options.TokenValidationParameters = GetNewSchemaTokenValidationParameters();
});
Тогда второй работает нормально, а первый не работает. Как я могу сделать аутентификацию обеих схем?