Security in ASP.NET Core MVC


On the Visual Studio, create new ASP.NET Core Web Application project

Select Empty Template

Click Ok button to Finish




Open Startup.cs file and add new configurations as below:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace LearnASPNETCoreMVCWithRealApps
{
    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(options =>
                {
                    options.LoginPath = "/Account/Index";
                    options.LogoutPath = "/Account/SignOut";
                    options.AccessDeniedPath = "/Account/AccessDenied";
                });
            services.AddMvc();
        }


        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseStaticFiles();

            app.UseMvc();

            app.UseAuthentication();

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

Create new folder named Models. In this folder, create new class named Account.cs as below:

Create new class named Account.cs as below:

namespace LearnASPNETCoreMVCWithRealApps.Models
{
    public class Account
    {
        public string Username { get; set; }

        public string Password { get; set; }

        public string[] Roles { get; set; }
    }
}




In Models folder, create new class named AccountModel.cs as below:

using System.Collections.Generic;
using System.Linq;

namespace LearnASPNETCoreMVCWithRealApps.Models
{
    public class AccountModel
    {
        private List<Account> accounts;

        public AccountModel()
        {
            accounts = new List<Account>();

            accounts.Add(new Account()
            {
                Username = "acc1",
                Password = "123",
                Roles = new string[] { "superadmin", "admin", "employee" }
            });

            accounts.Add(new Account()
            {
                Username = "acc2",
                Password = "123",
                Roles = new string[] { "admin", "employee" }
            });

            accounts.Add(new Account()
            {
                Username = "acc3",
                Password = "123",
                Roles = new string[] { "employee" }
            });
        }

        public Account find(string username)
        {
            return accounts.SingleOrDefault(a => a.Username.Equals(username));
        }

        public Account login(string username, string password)
        {
            return accounts.SingleOrDefault(a => a.Username.Equals(username) && a.Password.Equals(password));
        }

    }
}

Create Security folder in project. This folder contains class need for security in ASP.NET Core MVC as below:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using LearnASPNETCoreMVCWithRealApps.Models;
using System.Collections.Generic;
using System.Security.Claims;

namespace LearnASPNETCoreMVCWithRealApps.Security
{
    public class SecurityManager
    {
        public async void SignIn(HttpContext httpContext, Account account)
        {
            ClaimsIdentity claimsIdentity = new ClaimsIdentity(getUserClaims(account), CookieAuthenticationDefaults.AuthenticationScheme);
            ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
            await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
        }

        public async void SignOut(HttpContext httpContext)
        {
            await httpContext.SignOutAsync();
        }

        private IEnumerable<Claim> getUserClaims(Account account)
        {
            List<Claim> claims = new List<Claim>();
            claims.Add(new Claim(ClaimTypes.Name, account.Username));
            foreach (var role in account.Roles)
            {
                claims.Add(new Claim(ClaimTypes.Role, role));
            }
            return claims;
        }
    }
}




Create new folder named Controllers. In this folder, create new controllers as below:

Create new controller named DemoController.cs as below:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace LearnASPNETCoreMVCWithRealApps.Controllers
{
    public class DemoController : Controller
    {
        [AllowAnonymous]
        public IActionResult Index()
        {
            return View();
        }

        [Authorize(Roles = "superadmin")]
        public IActionResult Work1()
        {
            return View("Work1");
        }

        [Authorize(Roles = "superadmin,admin")]
        public IActionResult Work2()
        {
            return View("Work2");
        }

        [Authorize(Roles = "superadmin,admin,employee")]
        public IActionResult Work3()
        {
            return View("Work3");
        }
    }
}

Create new controller named AccountController.cs as below:

using Microsoft.AspNetCore.Mvc;
using LearnASPNETCoreMVCWithRealApps.Models;
using LearnASPNETCoreMVCWithRealApps.Security;

namespace LearnASPNETCoreMVCWithRealApps.Controllers
{
    public class AccountController : Controller
    {
        private SecurityManager securityManager = new SecurityManager();

        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Login(string username, string password)
        {
            AccountModel accountModel = new AccountModel();
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || accountModel.login(username, password) == null)
            {
                ViewBag.error = "Invalid";
                return View("Index");
            }
            else
            {
                securityManager.SignIn(this.HttpContext, accountModel.find(username));
                return RedirectToAction("Welcome");
            }
        }

        public IActionResult Welcome()
        {
            return View("Welcome");
        }

        public IActionResult AccessDenied()
        {
            return View("AccessDenied");
        }

        public IActionResult SignOut()
        {
            securityManager.SignOut(this.HttpContext);
            return RedirectToAction("Index");
        }
    }
}




Create new folder named Views. In this folder, create new views as below:

Create new folder named Account folder. In this folder, create new views as below:

Create new view named Index.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Login</title>
</head>
<body>

    <h3>Login Page</h3>
    @ViewBag.error
    <form method="post" asp-controller="account" asp-action="login">
        <table>
            <tr>
                <td>Username</td>
                <td>
                    <input type="text" name="username" />
                </td>
            </tr>
            <tr>
                <td>Password</td>
                <td>
                    <input type="password" name="password" />
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <input type="submit" value="Login" />
                </td>
            </tr>
        </table>
    </form>

</body>
</html>

Create new view named Welcome.cshtml as below:

@using System.Security.Claims;
@{
    var userId = User.FindFirst(ClaimTypes.Name);
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Welcome</title>
</head>
<body>

    <h3>Welcome Page</h3>
    Welcome @userId.Value
    <br />
    <a asp-controller="account" asp-action="SignOut">Logout</a>

</body>
</html>

Create new view named AccessDenied.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Access Denied</title>
</head>
<body>

    <h3>Access Denied Page</h3>

</body>
</html>

Createw new folder named Demo. In this folder, create new views as below:

Create new view named Index.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>

    <h3>Index Page</h3>

</body>
</html>

Create new view named Work1.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Work 1</title>
</head>
<body>

    <h3>Work 1 Page</h3>

</body>
</html>

Create new view named Work2.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Work 2</title>
</head>
<body>

    <h3>Work 2 Page</h3>

</body>
</html>

Create new view named Work3.cshtml as below:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Work 3</title>
</head>
<body>

    <h3>Work 3 Page</h3>

</body>
</html>




  • Access Index action in Account controller with following url: http://localhost:49328/Account/Index

    Output

  • Test access Index action in Demo controller without account with url: http://localhost:49328/Demo/Index

    Output

  • Test access Work1 action in Demo controller without account with url: http://localhost:49328/Demo/Work1

    Output

  • Test access Work2 action in Demo controller without account with url: http://localhost:49328/Demo/Work2

    Output

  • Test access Work3 action in Demo controller without account with url: http://localhost:49328/Demo/Work3

    Output

  • Test login with invalid account: username is abc and password is 456

    Output

  • Test login with valid account: username is acc2 and password is 123. This account have roles: admin and employee

    Output

  • Use acc2 has logged access Work1 action in Demo controller with url: http://localhost:49328/Demo/Work1

    Output

  • Use acc2 has logged access Work2 action in Demo controller with url: http://localhost:49328/Demo/Work2

    Output

  • Use acc2 has logged access Work3 action in Demo controller with url: http://localhost:49328/Demo/Work3

    Output