Asp.Net MVC 5 authentication and authorization using claims principal
Asp.Net MVC 5 authentication and authorization using claims principal :-
Step1 :
File -> New Project -> Asp.Net Web Application -> Asp.Net 4.5.2 Templates
Choose empty MVC project template
Step2 :
Install following nuget packages
Microsoft.AspNet.Identity.Core
Microsoft.AspNet.Identity.Owin
Microsoft.Owin
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security
Microsoft.Owin.Security.Cookies
Microsoft.Owin.Security.OAuth
Owin
Step3 :
Create a Owin Startup class and decorate with assembly attribute OwinStartup.
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;
[assembly: OwinStartup(typeof(AspNetMVC5Authorization.Startup))] // here "AspNetMVC5Authorization" is the name of project
namespace AspNetMVC5Authorization
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuthentication(app);
}
private void ConfigureAuthentication(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Auth/Login"), //sign page
CookieName = "AuthCookie",
CookieHttpOnly = true,
ExpireTimeSpan = System.TimeSpan.FromHours(1),
LogoutPath = new PathString("/Auth/Signout"), //sign out page
ReturnUrlParameter = "ReturnUrl",
CookieSecure = CookieSecureOption.SameAsRequest, //Use CookieSecureOption.Always if you intend to serve cookie in SSL/TLS (Https)
SlidingExpiration = true,
});
}
}
}
Step4 :
Create list of claims for the specific user with roles and other information
internal class AuthenticationHelper
{
internal static List<Claim> CreateClaim(UserSessionModel userSessionModel,params string[] roles) //Single or multiple roles
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, userSessionModel.UserId.ToString()), //User ideitifer
new Claim(ClaimTypes.Name, userSessionModel.DisplayName), //Username
new Claim(Constants.UserSession, userSessionModel.ToJson()) //Custom entity with user info
};
foreach (var role in roles) //custom roles goes here
{
claims.Add(new Claim(ClaimTypes.Role, role, ClaimValueTypes.String, Constants.Issuer));
}
return claims;
}
}
Step5 :
Create Authentication controller and process of the rest of the Authentication
namespace AspNetMVC5Authorization.Controllers
{
using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using System;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using Helpers;
using ViewModels;
public class AuthController : BaseController
{
[HttpGet]
public ActionResult SignIn()
{
if(UserSessionModel != null)
{
return Redirect("~/");
}
return View();
}
[HttpPost,ValidateAntiForgeryToken]
public ActionResult SignIn(SignInViewModel vm,string returnUrl = default(string))
{
try
{
if (!ModelState.IsValid)
{
vm.ErrorMessage = "Email address and Password are required fields";
return View(vm);
}
Authenticate(vm);
if (!string.IsNullOrWhiteSpace(returnUrl) && Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("index", "home");
}
catch (AuthenticationException e)
{
vm.ErrorMessage = e.Message;
}
return View(vm);
}
private void Authenticate(SignInViewModel vm)
{
if (vm.Email == "admin@gmail.com" && vm.Password == "password")
{
var userSession = new UserSessionModel
{
UserId = Guid.NewGuid(),
DisplayName = "Admin user",
UserRoleId = 1,
UserRoleName = "Admin"
};
var identity = new ClaimsIdentity(AuthenticationHelper.CreateClaim(userSession,
Helpers.Constants.UserRoles.Admin,
Helpers.Constants.UserRoles.User),
DefaultAuthenticationTypes.ApplicationCookie
);
AuthenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddHours(1)
}, identity);
}
else if (vm.Email == "user@gmail.com" && vm.Password == "password")
{
var userSession = new UserSessionModel
{
UserId = Guid.NewGuid(),
DisplayName = "User user",
UserRoleId = 2,
UserRoleName = "User"
};
var identity = new ClaimsIdentity(AuthenticationHelper.CreateClaim(userSession,
Helpers.Constants.UserRoles.User),
DefaultAuthenticationTypes.ApplicationCookie
);
AuthenticationManager.SignIn(new AuthenticationProperties()
{
AllowRefresh = true,
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddHours(1)
}, identity);
}
else
{
throw new AuthenticationException("Login failed. Incorrect email address or password");
}
}
public ActionResult Signout()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie,DefaultAuthenticationTypes.ExternalCookie);
return Redirect("~/");
}
private IAuthenticationManager AuthenticationManager
{
get { return HttpContext.GetOwinContext().Authentication; }
}
}
}
Step6 :
Get the custom ojbect obect from Claim
public class BaseController : Controller
{
protected internal UserSessionModel UserSessionModel { get; private set; }
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
var user = User as ClaimsPrincipal;
if (user != null)
{
var claims = user.Claims.ToList();
var sessionClaim = claims.FirstOrDefault(o => o.Type == Constants.UserSession);
if (sessionClaim != null)
{
UserSessionModel = sessionClaim.Value.ToObject<UserSessionModel>();
}
}
}
}
Step7 :
namespace AspNetMVC5Authorization.Helpers
{
internal static class Constants
{
internal const string UserSession = "UserSession";
internal const string Issuer = "https://yoursite.com";
internal static class UserRoles
{
internal const string Admin = "Admin";
internal const string User = "User";
}
}
}
Step8 :
namespace AspNetMVC5Authorization.Helpers
{
using Newtonsoft.Json;
public static class JsonSerializer
{
public static string ToJson<T>(this T t)
{
return JsonConvert.SerializeObject(t);
}
public static T ToObject<T>(this string data)
{
return JsonConvert.DeserializeObject<T>(data);
}
}
}
Step9 :
using System.Security.Claims;
using System.Web.Mvc;
namespace AspNetMVC5Authorization.Controllers
{
[Authorize(ClaimType = ClaimTypes.Role, ClaimValue = Helpers.Constants.UserRoles.Admin)]
public class AdminController : BaseController
{
// GET: Admin
public ActionResult Index()
{
return View();
}
}
}
Step10 :
using System.Security.Claims;
using System.Web.Mvc;
namespace AspNetMVC5Authorization.Controllers
{
[Authorize(ClaimType = ClaimTypes.Role, ClaimValue = Helpers.Constants.UserRoles.Admin + "," + Helpers.Constants.UserRoles.User)]
public class UserController : BaseController
{
// GET: User
public ActionResult Index()
{
return View();
}
}
}
Step11 :
Custom Authorize attribute code
namespace AspNetMVC5Authorization
{
using Helpers;
using System;
using System.Linq;
using System.Security.Claims;
using System.Web.Mvc;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
public string ClaimType { get; set; }
public string ClaimValue { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
var principal = filterContext.RequestContext.HttpContext.User as ClaimsPrincipal;
if (!principal.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult("~/auth/signin");
return;
}
var claimValue = ClaimValue.Split(',');
if (!(principal.HasClaim(x => x.Type == ClaimType && claimValue.Any(v => v == x.Value) && x.Issuer == Constants.Issuer)))
{
filterContext.Result = new RedirectResult("~/Unauthorize.html");
}
}
}
}
Step12 :
Master page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASP.NET Identity Application</title>
<link href="~/Content/Site.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="~/Scripts/modernizr-2.6.2.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
@if (HttpContext.Current.User.Identity.IsAuthenticated)
{
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="glyphicon glyphicon-user"></i><span> </span>@HttpContext.Current.User.Identity.Name<b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Profile</a></li>
<li class="divider"></li>
<li><a href="#">Change Password</a></li>
<li class="divider"></li>
<li><a href="/auth/signout">Sign out</a></li>
</ul>
</li>
if (HttpContext.Current.User.IsInRole("Admin")) // ye Helpers.Constants.UserRoles ke andar jo property ke naam ki value de rkhi he uske base pr ye work kr rha he.
{
<a href="#">Hello I am admin link</a>
}
}
else
{
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="glyphicon glyphicon-user"></i> <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="/auth/signin">Sign In</a></li>
</ul>
</li>
}
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
</body>
</html>
Comments
Post a Comment