Cookie authentication in ASP.NET Core 2 without ASP.NET Identity
The default ASP.NET Core 2 web template provides lots of code to authenticate users. My screen is not big enough to display all the files in the solution explorer. The template offers lots of functionalities: users can log in using username/password or using an external provider such as Google or Microsoft. You can use two-factor authentication. And so on.
You can rely on this code and use it as is. Or, if you just want to use cookie authentication, you can delete all these files, and create the sign-up and login pages by yourself. As you'll see in this post, the cookie authentication is very easy to use 😃
#Register the authentication middleware
First, add the NuGet package Microsoft.AspNetCore.Authentication.Cookies
. Then, you must configure and register the authentication middleware.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
app.UseMvc();
}
You are now ready to use the authentication functionalities 😃
#Create the LogIn model
public class LogInModel
{
[Required]
public string Username { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
#Create the LogIn page
ASP.NET Core 2 has a new way to create page: Razor Pages. Razor pages provide a way to create pages in a more understandable way. But you can easily transpose this code to use a Controller by just copying the code in the controller.
I create a new page Pages/login.cshtml
. The page contains a form
with two fields username
and password
and some bootstrap classes. A Razor Page starts with @page
.
@page
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="LogInModel.Username" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="LogInModel.Username" class="form-control" />
<span asp-validation-for="LogInModel.Username" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="LogInModel.Password" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="LogInModel.Password" class="form-control" />
<span asp-validation-for="LogInModel.Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<label asp-for="RememberMe">
<input asp-for="RememberMe" />
@Html.DisplayNameFor(m => m.RememberMe)
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">Log In</button>
</div>
</div>
</form>
Let's add some code to handle the button click. You can add the code directly to the page or create a PageModel
class. The code is very short, so I'll add it to the page.
@page
@using Microsoft.AspNetCore.Authentication;
@using Microsoft.AspNetCore.Authentication.Cookies;
@using System.Security.Claims;
@functions {
[BindProperty] // Bind on Post
public LogInModel LogInModel { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (ModelState.IsValid)
{
var isValid = true; // TODO Validate the username and the password with your own logic
if (!isValid)
{
ModelState.AddModelError("", "username or password is invalid");
return Page();
}
// Create the identity from the user info
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, LogInModel.Username));
identity.AddClaim(new Claim(ClaimTypes.Name, LogInModel.Username));
// You can add roles to use role-based authorization
// identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
// Authenticate using the identity
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = LogInModel.RememberMe });
return RedirectToPage("Index");
}
return Page();
}
}
<form>
...
</form>
As you can see, it's very simple 😃 Indeed, you just need to create an identity with the user data and call HttpContext.SignInAsync(...)
with the user data.
Now you can sign out using a single line of code:
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
#Conclusion
Cookie authentication is very easy to use. If you don't need to use all the functionalities provided by the default template, you can consider implementing them by yourself.
Do you have a question or a suggestion about this post? Contact me!