Reputation: 9488
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
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
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