Gup3rSuR4c
Gup3rSuR4c

Reputation: 9488

ASP.NET Core 2.0 Authentication NOT Working

I'm trying to implement authentication using Identity into my ASP.NET Core 2.0 project and it doesn't seem to be working. The last project I implement Identity into was an ASP.NET MVC 5 project, and things have changed substantially. I've skipped Core 1.0 and 1.1, so I have no knowledge of how it was done under those, though from what I'm reading it's supposed to be mostly similar.

I can't get it work for me though. When I say it's not working, I mean that I'm not being redirected to a login page even though I'm not authorized.

The only customization I've done is to implement my own user store and my own extension to add identity without the need for a role, since I'm not going to be using roles. I could use some direction on what I'm messing up because from my point of view everything is now way too complicated. Here's the code I've got so far:

Startup.cs

public void ConfigureServices(
    IServiceCollection services) {
    services.AddDbContext<CustomDbContext>();
    services.AddTransient<IUserStore<GlobalUser>, CustomUserStore<GlobalUser>>();
    services.AddIdentity<GlobalUser>();
    services.AddMvc();
}

public void Configure(
    IApplicationBuilder app,
    IHostingEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();
    app.UseAuthentication();
    app.UseMvc();
}

ServiceCollectionExtensions.cs

I just looked at the source for the built in AddIdentity<TUser, TRole> and omitted the role related stuff, so there shouldn't be an issue with it here, though maybe...

public static class ServiceCollectionExtensions {
    public static IdentityBuilder AddIdentity<TUser>(
        this IServiceCollection services,
        Action<IdentityOptions> optionsAction = null)
        where TUser : class {
        services.AddAuthentication(
            o => {
                o.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
                o.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
                o.DefaultSignInScheme = IdentityConstants.ApplicationScheme;
            }).AddCookie(
            o => {
                o.LoginPath = new PathString("/Login");
                o.Events = new CookieAuthenticationEvents {
                    OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
                };
            });

        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
        services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
        services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
        services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
        services.TryAddScoped<IdentityErrorDescriber>();
        services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
        services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
        services.TryAddScoped<UserManager<TUser>, AspNetUserManager<TUser>>();
        services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();

        if (optionsAction != null) {
            services.Configure(optionsAction);
        }

        return new IdentityBuilder(typeof(TUser), services);
    }
}

I thought I had to add the Authorize filter like in MVC 5, but I can't seem to do it globally. When I apply it to the default controller, I get the following exception:

No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

But I thought I was setting the scheme in my custom AddIdentity method? I could use some guidance and I appreciate any being sent my way.

Upvotes: 0

Views: 4944

Answers (2)

Gup3rSuR4c
Gup3rSuR4c

Reputation: 9488

I figured it out, and it was me overlooking something when I was making my own AddIdentity extension. I was supposed to pass in the IdentityConstants.ApplicationScheme as a parameter to AddCookie before passing in the options. I was double checking the Identity source and saw I was missing that. As soon as I added it, everything worked. So:

//           ▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼▼ this is what was missing
}).AddCookie(IdentityConstants.ApplicationScheme,
o => {

This was ultimately a problem of my own making...

Upvotes: 3

JohanP
JohanP

Reputation: 5472

I had the same issue as you. I had to implement custom auth based on FormsAuthentication cookie, which does not exist in .net core, we have some ASP.Net systems that use FormsAuthentication and we need interop. The way that I solved it was to subclass AuthorizeFilter and then override OnAuthorizationAsync(AuthorizationFilterContext context). This is what I cam up with:

public class AuthFilter : AuthorizeFilter
{

    public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        if (context.Filters.Any(item => item is IAsyncAuthorizationFilter && item != this || item is IAllowAnonymousFilter))
        {
            return Task.FromResult(0);
        }

        if (!context.HttpContext.User.Identity.IsAuthenticated)
        {
            context.Result = new UnauthorizedResult();
            return Task.FromResult(0);
        }

        return base.OnAuthorizationAsync(context);
    }

}

Then you have to go register that in Startup.cs in ConfigureServices i.e.

services.AddMvc(options =>
{
    options.Filters.Add(new AuthFilter(
        new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build()));
});

This will be default make ALL your Controllers need authorization. If you need anonymous login, go add [AllowAnonymous] to your Controller

Upvotes: 0

Related Questions