Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net Core 2.0 Authorization always returning 401

After adding [Authorize] to a controller, I'm always getting a 401 from it. While debugging, I see the return AuthenticateResult.Success being reached, but the code of the controller never is.
What am I doing wrong?

Below is the code for my Startup class and Custom auth classes.


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // ...

        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy", builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowAnyOrigin()
                .AllowCredentials());
        });

        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new RequireHttpsAttribute());
        });

        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = "Custom Scheme";
            options.DefaultChallengeScheme = "Custom Scheme";
        }).AddCustomAuth(o => { });

        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseCors("CorsPolicy");

        var options = new RewriteOptions().AddRedirectToHttps();
        app.UseRewriter(options);

        app.UseAuthentication();

        app.UseMvc();
    }
}

public class CustomAuthOptions : AuthenticationSchemeOptions
{
    public ClaimsIdentity Identity { get; set; }

    public CustomAuthOptions()
    {

    }
}

public static class CustomAuthExtensions
{
    public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action<CustomAuthOptions> configureOptions)
    {
        return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("Custom Scheme", "Custom Auth", configureOptions);
    }
}

internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
    public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
    {

    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        string token = Request.Headers["Authorization"];
        if (string.IsNullOrEmpty(token))
            return AuthenticateResult.Fail("Failing string");

        // Using external service to validate token and get user id
        int Id = GetUserId(token);

        return AuthenticateResult.Success(
            new AuthenticationTicket(
                new ClaimsPrincipal(
                    new ClaimsIdentity(
                        new List<Claim>() { new Claim(ClaimTypes.Sid, Id.ToString()) })),
                        Scheme.Name));
    }
}
like image 239
Matheus Lacerda Avatar asked Jan 22 '18 13:01

Matheus Lacerda


1 Answers

The problem is caused by the way you create an instance of ClaimsIdentity in CustomAuthHandler.HandleAuthenticateAsync(). The value of principal.Identity.IsAuthenticated will be false that makes AuthorizeAttribute to consider your request unathorized.

The reason why IsAuthenticated is set to false is described here in detail. To fix it, just use ClaimsIdentity constructor overload that takes authenticationType:

return AuthenticateResult.Success(
    new AuthenticationTicket(
        new ClaimsPrincipal(
            new ClaimsIdentity(
                new List<Claim>() { new Claim(ClaimTypes.Sid, Id.ToString()) }, Scheme.Name)),
        Scheme.Name));
like image 88
CodeFuller Avatar answered Dec 25 '22 10:12

CodeFuller