4

I'm following this walkthrough on integrating asp.net core identity with IdentityServer but have hit a few roadblocks.

Where I'm updating the ConfigureServices method, if I follow the guide and use

services.AddIdentity<IdentityUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

I can no longer access any of the account related functions. The routing for the register link changes from

~/Identity/Account/Register

to

~/?area=Identity&page=%2FAccount%2FRegister

Which breaks all account related functions

If I leave it at

services.AddDefaultIdentity<IdentityUser>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

Then the routing still works, I can enter my credentials via the login page and the login is successful, but

SignInManager.IsSignedIn(User)

returns false, so I'm guessing something is fundamentally broken here.

I have added identityserver to my ConfigureServices:

    services.AddIdentityServer()
                    .AddDeveloperSigningCredential()
                    .AddInMemoryPersistedGrants()
.AddInMemoryIdentityResources(Config.IdentityResources.GetIdentityResources())
                    .AddInMemoryApiResources(Config.APIResources.GetApiResources())
                    .AddInMemoryClients(Config.Clients.GetClients())
                    .AddAspNetIdentity<IdentityUser>();

Any ideas what needs to change - I'm guessing its something in the latest version of asp.net core that has caused this has it?

2
  • Do you have app.UseIdentityServer(); in Configure and is it before app.UseMvc()? Commented Oct 19, 2018 at 11:32
  • @KirkLarkin Yes, I have it eactly as per the quick start Commented Oct 19, 2018 at 11:40

3 Answers 3

5

The Identity UI is implemented using Razor Pages. For endpoint-routing to map these, add a call to MapRazorPages in your UseEndpoints callback:

app.UseEndpoints(endpoints =>
{
// ...
endpoints.MapRazorPages();
});
Sign up to request clarification or add additional context in comments.

2 Comments

Agree with @JhonnatanEduardo
It also works on .net 6
1

In Net Core 2.1 Microsoft have removed the AccountController and moved all the Identity logic to Razor pages (there is no alternative now available) which makes the logic difficult to follow (it reminds me of ASP classic or PHP). The Quickstart in the documentation relies entirely on the AccountController remaining in place (no longer the case) and guess this needs to be rewritten as Razor pages before anything will work. However, there is not a lot of point in doing this whilst the authentication mechanism is broken.

I used the following Startup.cs to demonstrate that authentication no longer works in IdentityServer4 when added to a new Net Core 2.1 project. It should work but shows the following behaviour when accessing a controller method protected by [Authorize] and the challenge presented as a Login page.

1) Entering the incorrect credentials causes the 'Invalid login attempt' text to be displayed

2) Entering correct credentials fails to authenticate and this can be seen by there being no Logout link or debugging and observing User.isAuthenticated is false

A couple of changes can be made to the Startup.cs in order to show authentication works when IdentityServer is disabled and the standard authentication enabled. Simply comment out the block commencing 'services.AddIdentityServer(options => ' to disable IdentityServer. Next comment out 'useIdentityServer()' and uncomment 'useAuthentication()' and all the authentications work correctly again.

  public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.Lax;
        });

        // Add authentication options
        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";
            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;
            options.ClientId = "mvc";
            options.ClientSecret = "secret";
            options.ResponseType = "code id_token";
            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = true;
            options.Scope.Add("api1");
            options.Scope.Add("offline_access");

        });

        // Identity Context
        services.AddDbContext<ApplicationDbContext>(options =>
        {
            options.UseSqlServer(Configuration["IdentityConnection"],
                                sqlOptions => sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().
                                Assembly.GetName().Name));
        },
            ServiceLifetime.Scoped
        );

        // Configure default Identity implementation
        services.AddDefaultIdentity<ApplicationUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultUI()
            .AddDefaultTokenProviders()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // Add application services.
        services.AddTransient<Microsoft.AspNetCore.Identity.UI.Services.IEmailSender, EmailSender>();

        services.AddMvc();

        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer(options =>
        {
            options.UserInteraction.LoginUrl = "/Identity/Account/Login";
            options.UserInteraction.LogoutUrl = "/Identity/Account/Logout";
        })
        .AddDeveloperSigningCredential()
            .AddInMemoryPersistedGrants()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddAspNetIdentity<ApplicationUser>();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        //app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
        app.UseIdentityServer();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

I'm not sure how to the authentication working in IdentityServer4 since have not followed how it would work in Net Core 2.1. Has anyone got further than me and got this server working?

Comments

1

Figured this out in the end. Seems like a weird bug as MSFT migrates to Razor pages. All I needed to do was add in the Scaffolding UI and it just started working

1 Comment

Adding app.MapRazorPages() after app.MapControllerRoute(...) fixed it for me, before that it was making the path into query string parameters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.