Asp.net core Identity successful login redirecting back to login page
In order to get the ASP.NET Core pipeline to recognise that a user is signed in, a call to UseAuthentication
is required in the Configure
method of your Startup
class, like so:
app.UseAuthentication();
app.UseMvc(); // Order here is important (explained below).
Using the Cookies authentication scheme, the use of UseAuthentication
loosely performs the following:
- Reads the content of the
.AspNetCore.Identity.Application
cookie from the request, which represents the identity of the user making the request. - Populates the
User
property ofHttpContext
with aClaimsPrincipal
that represents said user.
This is a simplified explanation of what happens, but it highlights the important job that the authentication middleware performs. Without the authentication middleware, the .AspNetCore.Identity.Application
will not be used for authenticating the user and therefore the user will not be authenticated. In your case, although the user has signed in (i.e. the cookie is being set), the pipeline middleware (e.g. MVC) does not see this user (i.e. the cookie is not being read) and so sees an unauthenticated request and redirects again for login.
Given that the authentication middleware reads the cookie and subsequently populates the ClaimsPrincipal
, it should be clear that the UseAuthentication
call must also be before the UseMvc
call in order for this to occur in the correct order. Otherwise, the MVC middleware runs before the Authentication middleware and will not be working with a populated ClaimsPrincipal
.
Why is it failing to login if you don't add the middleware that handles the login?!?
The middleware doesn't handle the login - it handles the authentication process. The user has logged in, which is confirmed by the presence of the .AspNetCore.Identity.Application
cookie. What is failing here is the reading of said cookie.
.Net Core 5 Razor pages Cookie Authentication redirects to the login page after successful login
Do not know the exact reason but changing the default authentication scheme worked for me.
In your startup.cs file, change
from this:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Identity/Account/Login";
options.ExpireTimeSpan = new System.TimeSpan(0, 10, 0);
options.SlidingExpiration = true;
options.Cookie = new CookieBuilder
{
SameSite = SameSiteMode.Strict,
SecurePolicy = CookieSecurePolicy.Always,
IsEssential = true,
HttpOnly = true
};
options.Cookie.Name = "Authentication";
});
to this:
services.AddAuthentication(IdentityConstants.ApplicationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Identity/Account/Login";
options.ExpireTimeSpan = new System.TimeSpan(0, 10, 0);
options.SlidingExpiration = true;
options.Cookie = new CookieBuilder
{
SameSite = SameSiteMode.Strict,
SecurePolicy = CookieSecurePolicy.Always,
IsEssential = true,
HttpOnly = true
};
options.Cookie.Name = "MyCookie";
});
Able to go to login page even after been logged in
You can customize a middleware to redirect when user logged in and access the login page.
RedirectMiddleware.cs
public class RedirectMiddleware
{
private readonly RequestDelegate _next;
public RedirectMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if(context.Request.Path == "/Identity/Account/Login")
{
if (context.User.Identity.IsAuthenticated)
{
context.Response.Redirect("/Home/Index");
}
}
await _next.Invoke(context);
}
}
Startup.cs
app.UseMiddleware<RedirectMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
Or
Directly do the redirection in the Login OnGetAsync Handler:
public async Task OnGetAsync(string returnUrl = null)
{
if (!string.IsNullOrEmpty(ErrorMessage))
{
ModelState.AddModelError(string.Empty, ErrorMessage);
}
if (User.Identity.IsAuthenticated)
{
Response.Redirect("/Home/Index");
}
returnUrl = returnUrl ?? Url.Content("~/");
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
ReturnUrl = returnUrl;
}
Authorized page redirects back to login after successful login
In your Github project, you have a site.js
file that contains (amongst other things), the following jQuery event-handler:
$('form[method=post]').not('.no-ajax').on('submit', function () {
...
$.ajax({
url: $this.attr('action'),
...
statusCode: {
200: redirect
},
...
}).error(highlightErrors);
return false;
}
When you submit your login form, you end up running through this block of code above, which then invokes your redirect
callback function for a statusCode
of 200
, shown below:
var redirect = function (data) {
if (data.redirect) {
window.location = data.redirect;
} else {
window.scrollTo(0, 0);
window.location.reload();
}
};
In the scenario you've described, data.redirect
is undefined
. In that case, you end up calling window.location.reload()
, which, of course, reloads the login page and explains the issue you've been having clearly.
Here's a step-by-step breakdown of what happens:
- The submit event is triggered when clicking "Log In".
- The browser-based POST is intercepted, being sent instead as an XHR request.
- The server logs in the user, assigns the cookie and returns a 302 response for redirecting to
/Home/About
. - The XHR internal mechanics follows the redirect and pulls down the HTML for the
/Home/About
page. - Your Javascript
redirect
callback is invoked wheredata
represents the response to the/Home/About
page (thetext/html
response). - Finally, whilst still on the
/Account/Login
page, the page is reloaded as described above.
Due to how you've set up the jQuery selector shown in the first code snippet, you can simply add the no-ajax
class to your login form and it will behave as expected.
Change the Identity Login's success url instead /Home/Index in .NET core
You'll need to scaffold in the Login
page (if you haven't already) and change it in the code behind. However, that's just the default if no returnUrl is provided. Normally, the user will be prompted to login because they've attempted to go to some area that requires authorization, such as /Dashboard/Index
in your scenario. If they navigate to /Dashboard/Index
and are redirected to the login page to authenticate, then they will be redirected back to /Dashboard/Index
once they're logged in.
.NET Core Identity after successful login go back to login page
I think a good practice is to not mix IdentityServer with your SPA application, I think its better to keep them separate. When you follow the separation of concerns principles then is that troubleshooting is easier.
I would also place
app.UseAuthorization();
Directly after
app.UseAuthentication();
You should not use appUseMvc() and UseEndpoints() at the same time. Remove UseMVC(). See this document Migrate from ASP.NET Core 2.2 to 3.0
google authentication stuck when redirecting back to my website
Finally after a week i found the problem, it was not in the code it was the server.
The IIS limits the query string character count (i think the default is 260 character) and in my case google responds with a query string with 544 character in which the IIS does not accept or respond to so it stays stuck on the SetSID page
Here is where i found the solution to increase the query string max length
Increase max url length in asp.net core
as of why it was working and then stopped this i could not figure it out
Related Topics
Return Json, But It Includes Backward Slashes "\", Which I Don't Want
How to Make a Soap/Wsdl Client in C#
How to Delete Records Between Two Dates in Bulk
Data Binding in MVC 5 and Select2 Multiple Values With Razor Engine
Securely Store a Password in the Application in C#
Searching If Value Exists in a List of Objects Using Linq
C# String to Hex , Hex to Byte Conversion
How to Create ASP.NET Identity Tables in an Already Created Database Using Code First
How to Delete All Files in an Azure File Storage Folder
How to Call Another Controller Action from a Controller in MVC
How to Trigger Event When a Variable'S Value Is Changed
How to Convert a List to Ienumerable
How to Create a Dynamic Email Template That Can Be Modified Without Changing Code in C# .Net MVC
How to Extract Custom Header Value in Web API Message Handler
How to Pass Multiple Arguments in Processstartinfo
How to Determine If a Json Object Contains Only a Specific Key
Split a Comma-Separated String With Both Quoted and Unquoted Strings