I have a .NET Core 2.0 app and have a problem with authorization. I want to use custom authorization with special requests. Header and standard default authentication. First, I add configuration in Startup.cs
:
public IServiceProvider ConfigureServices(IServiceCollection services) { // ... services.AddAuthorization(options => { options.AddPolicy(DefaultAuthorizedPolicy, policy => { policy.Requirements.Add(new TokenAuthRequirement()); }); }); services.AddSingleton<IAuthorizationHandler, AuthTokenPolicy>(); // ... }
AuthTokenPolicy.cs
:
public class AuthTokenPolicy : AuthorizationHandler<TokenAuthRequirement> { protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TokenAuthRequirement requirement) { var filterContext = context.Resource as AuthorizationFilterContext; var response = filterContext.HttpContext.Response; try { // some validation code var isValidToken = isValidTokenTask.Result; if (!isValidToken) { response.StatusCode = 401; return Task.CompletedTask; } response.StatusCode = 200; context.Succeed(requirement); } catch (Exception) { return Task.CompletedTask; } return Task.CompletedTask; } }
and in HomeController.cs
:
[Authorize(Policy = Startup.DefaultAuthorizedPolicy)] public async Task<IActionResult> IsVisible()
If I use the wrong request.header in AuthTokenPolicy
I see it, but in the logs I see this error:
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.\r\n at Microsoft.AspNetCore.Authentication.AuthenticationService.d__11.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.ChallengeResult.d__14.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__19.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__17.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__15.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at React.AspNet.BabelFileMiddleware.d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at core.common.Middleware.LoggingMiddleware.d__3.MoveNext() in D:\Dev\microservicePDP\Template\core.common\Middleware\LoggingMiddleware.cs:line 72
After reading Migrating Authentication and Identity to ASP.NET Core 2.0 I've added this code in startup.cs
Quotation from the article :
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; });
Define a default scheme in 2.0 if one of the following conditions is true: You want the user to be automatically signed in You use the [Authorize] attribute or authorization policies without specifying schemes
I added AuthenticationScheme
and DefaultChallengeScheme
in ConfigureServices()
. It didn't help, the same error here. I've tried to use app.UseAuthentication();
in the Startup.Configure()
method, with no results.
How can I use a custom authorization without authentication?
Calling AddAuthentication(JwtBearerDefaults. AuthenticationScheme) simply enables authentication and sets “Bearer” as the default scheme. This means, when you use [Authorize] without specifying an authentication scheme, it will by default challenge the user using the handler configured for “Bearer”.
AuthenticationScheme is the name of the scheme to use by default when a specific scheme isn't requested. If multiple schemes are used, authorization policies (or authorization attributes) can specify the authentication scheme (or schemes) they depend on to authenticate the user.
Do not use authorization instead of authentication. I should get whole access to service all clients with header.
The working code is:
public class TokenAuthenticationHandler : AuthenticationHandler<TokenAuthenticationOptions> { public IServiceProvider ServiceProvider { get; set; } public TokenAuthenticationHandler (IOptionsMonitor<TokenAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IServiceProvider serviceProvider) : base (options, logger, encoder, clock) { ServiceProvider = serviceProvider; } protected override Task<AuthenticateResult> HandleAuthenticateAsync () { var headers = Request.Headers; var token = "X-Auth-Token".GetHeaderOrCookieValue (Request); if (string.IsNullOrEmpty (token)) { return Task.FromResult (AuthenticateResult.Fail ("Token is null")); } bool isValidToken = false; // check token here if (!isValidToken) { return Task.FromResult (AuthenticateResult.Fail ($"Balancer not authorize token : for token={token}")); } var claims = new [] { new Claim ("token", token) }; var identity = new ClaimsIdentity (claims, nameof (TokenAuthenticationHandler)); var ticket = new AuthenticationTicket (new ClaimsPrincipal (identity), this.Scheme.Name); return Task.FromResult (AuthenticateResult.Success (ticket)); } }
Startup.cs:
#region Authentication services.AddAuthentication (o => { o.DefaultScheme = SchemesNamesConst.TokenAuthenticationDefaultScheme; }) .AddScheme<TokenAuthenticationOptions, TokenAuthenticationHandler> (SchemesNamesConst.TokenAuthenticationDefaultScheme, o => { }); #endregion
And mycontroller.cs:
[Authorize(AuthenticationSchemes = SchemesNamesConst.TokenAuthenticationDefaultScheme)] public class MainController : BaseController { ... }
I can't find TokenAuthenticationOptions now, but it was empty. I found the same class PhoneNumberAuthenticationOptions:
public class PhoneNumberAuthenticationOptions : AuthenticationSchemeOptions { public Regex PhoneMask { get; set; }// = new Regex("7\\d{10}"); }
You should define static class SchemesNamesConst
. Something like:
public static class SchemesNamesConst { public const string TokenAuthenticationDefaultScheme = "TokenAuthenticationScheme"; }
this worked for me
// using Microsoft.AspNetCore.Authentication.Cookies; // using Microsoft.AspNetCore.Http; services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.LoginPath = new PathString("/auth/login"); options.AccessDeniedPath = new PathString("/auth/denied"); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With