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.
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...