-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Summary
I need a way to disable authentication completely so no User would be present in method's context.
I made a solution but I doubt if it is good enough.
Details
I have a method with custom authentication based on request parameters, so I need its context to be free of authenticated users before I call my authentication, or it will break. My application has cookie and JWT authentication method, and user will be authenticated if a token or cookie would be attached to the request if I'm using plain [Authorize] + [AllowAnonymous].
Solution
My solution was to create custom AuthenticationScheme that would fail to authorize anything, then use it as the only one for my method. A custom AuthorizationPolicy was required to do so.
Question is, is there a better way to solve my problem, and does this approach have any critical issues?
public class AlwaysFailRequirement : IAuthorizationRequirement {}
public class AlwaysFailAuthorizationHandler : AuthorizationHandler<AlwaysFailRequirement> {
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AlwaysFailRequirement requirement) {
context.Fail();
return Task.CompletedTask;
}
}
public class AlwaysFailAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> {
public AlwaysFailAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) {
}
protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
return Task.FromResult(AuthenticateResult.Fail("Blocking Authentication is called"));
}
}
public static class AlwaysFailAuthExtension {
public const string AuthenticationScheme = "SchemeAlwaysFail";
public const string AuthorizationPolicy = "PolicyAlwaysFail";
// Is called on initialization
public static IServiceCollection AddAlwaysFailingAuthPolicy(this IServiceCollection services) {
services.AddAuthentication().AddScheme<AuthenticationSchemeOptions, AlwaysFailAuthenticationHandler>(AuthenticationScheme, null, authenticationScheme => {});
services.AddAuthorization(options => options.AddPolicy(AuthorizationPolicy,
policy => {
policy.AuthenticationSchemes = new[] { AuthenticationScheme };
policy.AddRequirements(new AlwaysFailRequirement());
}));
services.AddScoped<IAuthorizationHandler, AlwaysFailAuthorizationHandler>();
return services;
}
}
[ApiController]
[Authorize(Policy = AlwaysFailAuthExtension.AuthorizationPolicy)]
public class MyAuthenticationController : ControllerBase {
// ...
[AllowAnonymous]
[HttpPost]
public IActionResult Authenticate( ... ) {
//if (this.HttpContext.User != null) throw "User already logged";
// ...
}
// ...
}