MVC authentication and authorization, custom Filters example
Login Class
public class UserLogon
{
[Required]
[Display(Name = "User
Login")]
public string
UserName { get; set;
}
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string
Password { get; set;
}
}
Account Controller
using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Web.Security;
using System.Web.Mvc;
namespace MvcTextApplication.Controllers
{
public class AccountController : Controller
{
public ActionResult
LogOn()
{
return View();
}
//
// POST: /Account/LogOn
[HttpPost]
public ActionResult
LogOn(UserLogon model, string returnUrl)
{
if (ModelState.IsValid)
{
string Role = "";
// Passw0rd can be get from database
// I am assigning one common password
string password = "common";
// Role can be get from database also
// I am assigning roles manually
if (model.UserName == "adminuser")
{
Role = "Admin";
}
else if
(model.UserName == "staffuser")
{
Role = "SU";
}
else
{
Role = "Others";
}
if (string.IsNullOrEmpty(model.UserName)
|| string.IsNullOrEmpty(model.Password))
{
ModelState.AddModelError("",
"The user login or password provided is
incorrect.");
}
// we are checking here if Passowrd entered by
user is same as our password eg: common
if (model.Password == password)
{
// create FormsAuthenticationTicket
var authTicket = new FormsAuthenticationTicket(
1, // version
model.UserName, // user name
DateTime.Now, //
created
DateTime.Now.AddMinutes(20), // expires
false, // persistent?
Role.ToString() // can
be used to store roles
);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket);
System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);
if (Url.IsLocalUrl(returnUrl) &&
returnUrl.Length > 1 && returnUrl.StartsWith("/")
&&
!returnUrl.StartsWith("//")
&& !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("../Security/Index");
}
}
else
{
ModelState.AddModelError("",
"The password provided is incorrect.");
}
}
return View(model);
}
public ActionResult
LogOff()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index",
"Home");
}
}
}
Login View
<h2>LogOn</h2>
<script src="<%:
Url.Content("~/Scripts/jquery.validate.min.js") %>" type="text/javascript"></script>
<script src="<%:
Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js") %>" type="text/javascript"></script>
<% using
(Html.BeginForm()) { %>
<%: Html.ValidationSummary(true)
%>
<fieldset>
<legend>UserLogon</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.UserName) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.UserName) %>
<%: Html.ValidationMessageFor(model =>
model.UserName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Password) %>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.Password) %>
<%: Html.ValidationMessageFor(model =>
model.Password) %>
</div>
<p>
<input type="submit" value="Login" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back
to List", "Index") %>
</div>
We can see in Controller class that if user Login adminuser then role would be Admin and if user Login is staffuser then role would be SU other role would be Others
Custom Error View :
<%@ Page
Title=""
Language="C#"
MasterPageFile="~/Views/Shared/MasterPage.Master"
Inherits="System.Web.Mvc.ViewPage<dynamic>"
%>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<h2>Custom Error Page </h2> <br /><br />
<%= (string)ViewBag.ErrorMessage
%>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder2" runat="server">
</asp:Content>
Security Controller class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcTextApplication.Controllers
{
[HandleError]
public class SecurityController : Controller
{
//Can be accessed by anonymous users
public ActionResult
Index()
{
ViewData["Message"] = "Welcome to My website";
return View();
}
[CustomAuthorizeSecod]
public ActionResult
About()
{
ViewData["Message"] = "Welcome to My website About Page";
return View();
}
[Authorize]
public ActionResult
AuthenticatedUsers()
{
ViewData["Message"] = "Welcome to My website Authenticated Users
Page";
return View();
}
[Authorize(Users = "staffuser")]
public ActionResult
Users()
{
ViewData["Message"] = "Welcome
to My website Authenticated Specific users";
return View();
}
[Authorize(Roles = "Admin,SU")]
public ActionResult
Roles()
{
ViewData["Message"] = "Welcome to My website Authenticated Users admin adn
SU Page";
return View();
}
}
}
CustomAuthorizeSecod Class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
public class CustomAuthorizeSecod : FilterAttribute,
IAuthorizationFilter
{
public void
OnAuthorization(AuthorizationContext
filterContext)
{
var Controller =
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var Action =
filterContext.ActionDescriptor.ActionName;
var User =
filterContext.HttpContext.User;
var IP =
filterContext.HttpContext.Request.UserHostAddress;
if
(filterContext.HttpContext.Request.IsAuthenticated)
{
if
(filterContext.HttpContext.User.IsInRole("Admin"))
{
return;
}
else
{
ViewResult
result = new ViewResult();
result.ViewName = "../Error/CustomError";
result.ViewBag.ErrorMessage = "You are
not authenticated. Please log-in and try again!";
filterContext.Result = result;
//
}
}
}
else
{
ViewResult result = new ViewResult();
result.ViewName = "../Error/CustomError";
result.ViewBag.ErrorMessage = "You are
not authenticated. Please log-in and try again!";
filterContext.Result = result;
}
}
}
Important Steps:
Webconfig File : Add following code
<authentication mode="Forms">
<forms loginUrl="~/Account/Logon" timeout="2880" />
</authentication>
Global File : Add
following code
protected void
Application_AuthenticateRequest(Object
sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null
|| authCookie.Value == "")
return;
FormsAuthenticationTicket authTicket;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch
{
return;
}
// retrieve roles from UserData
string[] roles = authTicket.UserData.Split(';');
if (Context.User != null)
Context.User = new GenericPrincipal(Context.User.Identity, roles);
}
Login as AdminUser
Role =Admin
Redirected to following screen
Type following URL
Which will call Following method
[Authorize(Users = "staffuser")]
public ActionResult
Users()
{
ViewData["Message"] = "Welcome to My website Authenticated Specific
users";
return View();
}
Only staffuser can access this Action method so browser redirect to Logon view
which we specify in WEBCONFIG FILE