I have a web app written in ASP .Net Core 1.1 MVC. I am using Auth0 as the authentication server. After a successful login, the Index page should show the logged in user's name, but it's not. If I look at my _Layout.cshtml view:
@if (User.Identity.IsAuthenticated) {<li><a asp-controller="Account" asp-action="Profile">Hello @User.Identity.Name!</a></li><li><a asp-controller="Account" asp-action="Logout">Logout</a></li> } else {<li><a asp-controller="Account" asp-action="Login" asp-route-returnUrl="@Url.Action("Index", "Home")'">Login</a></li> }
@User.Identity.Name is null. But because I'm quite new to ASP and authentication, I'm struggling to figure out why...
One thing that is of concern to me, and I don't know if it might be related, is that after the user logs in, he gets redirected to the wrong place (instead of redirecting to the home page or something like that (http://localhost:60856/), it redirects to http://localhost:60856/' As you can see there is an apostrophe at the end, and I don't know why that's happening, and if that has anything to do with anything...
This is my Startup.cs file (sorry, it's quite long!)
public class Startup { public IConfigurationRoot Configuration { get; } public IHostingEnvironment HostingEnvironment { get; } public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); if (env.IsDevelopment()) builder.AddUserSecrets<Startup>(); builder.AddEnvironmentVariables(); Configuration = builder.Build(); HostingEnvironment = env; } public void ConfigureServices(IServiceCollection services) { services.AddAuthentication( options => options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); services.AddMvc(); services.AddOptions(); services.Configure<Auth0Settings>(Configuration.GetSection("Auth0")); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IOptions<Auth0Settings> auth0Settings) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); // Add the cookie middleware app.UseCookieAuthentication(new CookieAuthenticationOptions { AutomaticAuthenticate = true, AutomaticChallenge = true, Events = new CookieAuthenticationEvents() { OnRedirectToLogin = ctx => { // if it is an ajax / api request, don't redirect to login page. if (!(IsAjaxRequest(ctx.Request) || IsApiRequest(ctx.Request))) { ctx.Response.Redirect(ctx.RedirectUri); return Task.CompletedTask; } ctx.Response.StatusCode = StatusCodes.Status401Unauthorized; return ctx.Response.WriteAsync("Unauthorized"); } } }); // Add the OIDC middleware var options = new OpenIdConnectOptions("Auth0") { // Set the authority to your Auth0 domain Authority = $"https://{auth0Settings.Value.Domain}", // Configure the Auth0 Client ID and Client Secret ClientId = auth0Settings.Value.ClientId, ClientSecret = auth0Settings.Value.ClientSecret, // Do not automatically authenticate and challenge AutomaticAuthenticate = false, AutomaticChallenge = false, // Set response type to code ResponseType = OpenIdConnectResponseType.Code, // Set the callback path, so Auth0 will call back to http://localhost:5000/signin-auth0 // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard CallbackPath = new PathString("/signin-auth0"), //CallbackPath = new PathString("/signin-auth0"), // Configure the Claims Issuer to be Auth0 ClaimsIssuer = "Auth0", // The UserInfo endpoint does not really return any extra claims which were not returned in the original auth response, so // we can save ourselves from making an extra request GetClaimsFromUserInfoEndpoint = false, // Saves tokens to the AuthenticationProperties SaveTokens = true, Events = new OpenIdConnectEvents { OnTicketReceived = context => { // Get the ClaimsIdentity var identity = context.Principal.Identity as ClaimsIdentity; if (identity != null) { // Add the Name ClaimType. This is required if we want User.Identity.Name to actually return something! if (!context.Principal.HasClaim(c => c.Type == ClaimTypes.Name) && identity.HasClaim(c => c.Type == "name")) identity.AddClaim(new Claim(ClaimTypes.Name, identity.FindFirst("name").Value)); // Check if token names are stored in Properties if (context.Properties.Items.ContainsKey(".TokenNames")) { // Token names a semicolon separated string[] tokenNames = context.Properties.Items[".TokenNames"].Split(';'); // Add each token value as Claim foreach (var tokenName in tokenNames) { // Tokens are stored in a Dictionary with the Key ".Token.<token name>" string tokenValue = context.Properties.Items[$".Token.{tokenName}"]; identity.AddClaim(new Claim(tokenName, tokenValue)); } } } return Task.CompletedTask; }, OnRedirectToIdentityProvider = context => { context.ProtocolMessage.Parameters.Add("audience", auth0Settings.Value.ApiIdentifier); return Task.CompletedTask; }, //handle the logout redirection OnRedirectToIdentityProviderForSignOut = (context) => { var logoutUri = $"https://{auth0Settings.Value.Domain}/v2/logout?client_id={auth0Settings.Value.ClientId}"; var postLogoutUri = context.Properties.RedirectUri; if (!string.IsNullOrEmpty(postLogoutUri)) { if (postLogoutUri.StartsWith("/")) { // transform to absolute var request = context.Request; postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri; } logoutUri += $"&returnTo={ Uri.EscapeDataString(postLogoutUri)}"; } context.Response.Redirect(logoutUri); context.HandleResponse(); return Task.CompletedTask; } }, }; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("name"); options.Scope.Add("email"); options.Scope.Add("picture"); options.Scope.Add("country"); options.Scope.Add("roles"); app.UseOpenIdConnectAuthentication(options); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } private static bool IsAjaxRequest(HttpRequest request) { var query = request.Query; if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest")) { return true; } IHeaderDictionary headers = request.Headers; return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest")); } private static bool IsApiRequest(HttpRequest request) { return request.Path.StartsWithSegments(new PathString("/api")); } }