Cookie authentication in ASP.NET Core 2 without ASP.NET Identity

 
 
  • Gérald Barré

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.

C#
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

C#
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.

HTML
@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.

HTML
@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:

C#
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!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub