ASP.NET MVC Forms Authentication + Authorize Attribute + Simple Roles

I am trying to add simple authentication and authorization to an ASP.NET MVC application.

I'm just trying to use some additional features for basic forms authentication (thanks to the simplicity and customizable database structure).

Assuming this is my database structure: User: username password (ideally, some are listed. Strings, if necessary. Currently, the user has only one role, but this can change)

High Level Problem: Given the above database structure, I would like to be able to do the following:

  • Simple login using forms authentication
  • Decorate my actions with: [Authorize (Roles = {MyRoles.Admin, MyRoles.Member})]
  • Use roles in my views (to define links to display in some particles)

Currently, all I'm really sure of is authentication. After that I got lost. I'm not sure at what point I will seize the user role (login, each authorization?). Since my roles cannot be strings, I'm not sure how they will fit into User.IsInRole ().

Now I am asking here because I have not found a “simple” solution that I need. I have seen some examples.

For authentication:

  • We have a simple user check that checks the database and "SetAuthCookie"
  • Or we redefine the membership provider and do it inside ValidateUser. In any of them I’m not sure how to use my simple user roles to work with: HttpContext.Current.User.IsInRole ("Administrator") Also, I'm not sure how change this to work with my enum values.

For authorization, I saw:

  • Obtaining AuthorizeAttribute authority and implementing AuthorizeCore OR OnAuthorization to handle roles?
  • IPrincipal implementation?

Any help would be greatly appreciated. However, I am afraid that I may need a lot of details, because none of what I was looking for Google seems to match what I need to do.

+53
authorization asp.net-mvc forms-authentication
Sep 06 '09 at 6:43
source share
5 answers

Create a custom AuthorizeAttribute that can use your enumerations, not strings. When you need to log in, convert the enumerations into strings by adding the enumeration type name + enumeration value and use IsInRole from there.

To add roles to an authorized user, you need to attach to the HttpApplication AuthenticateRequest event something like the first code in http://www.eggheadcafe.com/articles/20020906.asp (but invert the massively nested if statements to security points!).

You can use user roles in cookies for authentication or retrieve them from the database each time.

+8
Oct 10 '09 at 2:52
source share

I think I implemented something similar.
My solution, based on the NerdDinner tutorial , is as follows.

When you sign up the user at , add code similar to the following:

 var authTicket = new FormsAuthenticationTicket( 1, // version userName, // user name DateTime.Now, // created DateTime.Now.AddMinutes(20), // expires rememberMe, // persistent? "Moderator;Admin" // 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); 

Add the following code to Global.asax.cs :

 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); } 

After that, you can use the [Authorize] attribute in the action code of your controller:

 [Authorize(Roles="Admin")] public ActionResult AdminIndex () 

Please let me know if you have further questions.

+118
Feb 26 '10 at 14:21
source share

I did something like this:

  • Use Global.asax.cs to load the role that you want to compare in the session, cache or application state, or load them on the fly on the ValidateUser controller.

Assign the [Authorize] attribute to your controllers, which requires permission to

  [Authorize(Roles = "Admin,Tech")] 

or allow access, for example, Login and ValidateUser controllers use the attribute below

  [AllowAnonymous] 

My login form

 <form id="formLogin" name="formLogin" method="post" action="ValidateUser"> <table> <tr> <td> <label for="txtUserName">Username: (AD username) </label> </td> <td> <input id="txtUserName" name="txtUserName" role="textbox" type="text" /> </td> </tr> <tr> <td> <label for="txtPassword">Password: </label> </td> <td> <input id="txtPassword" name="txtPassword" role="textbox" type="password" /> </td> </tr> <tr> <td> <p> <input id="btnLogin" type="submit" value="LogIn" class="formbutton" /> </p> </td> </tr> </table> @Html.Raw("<span id='lblLoginError'>" + @errMessage + "</span>") </form> 

Login controller and ValidateUser controller called from form message

Verifying user authentication through the WCF service, which verifies the local Windows AD service for the service, but you can change it to your own authentication mechanism.

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; using System.Security.Principal; using MyMVCProject.Extensions; namespace MyMVCProject.Controllers { public class SecurityController : Controller { [AllowAnonymous] public ActionResult Login(string returnUrl) { Session["LoginReturnURL"] = returnUrl; Session["PageName"] = "Login"; return View("Login"); } [AllowAnonymous] public ActionResult ValidateUser() { Session["PageName"] = "Login"; ViewResult retVal = null; string loginError = string.Empty; HttpContext.User = null; var adClient = HttpContext.Application.GetApplicationStateWCFServiceProxyBase.ServiceProxyBase<UserOperationsReference.IUserOperations>>("ADService").Channel; var username = Request.Form["txtUserName"]; var password = Request.Form["txtPassword"]; //check for ad domain name prefix if (username.Contains(@"\")) username = username.Split('\\')[1]; //check for the existence of the account var acctReq = new UserOperationsReference.DoesAccountExistRequest(); acctReq.userName = username; //account existence result var accountExist = adClient.DoesAccountExist(acctReq); if (!accountExist.DoesAccountExistResult) { //no account; inform the user return View("Login", new object[] { "NO_ACCOUNT", accountExist.errorMessage }); } //authenticate var authReq = new UserOperationsReference.AuthenticateRequest(); authReq.userName = username; authReq.passWord = password; var authResponse = adClient.Authenticate(authReq); String verifiedRoles = string.Empty; //check to make sure the login was as success against the ad service endpoint if (authResponse.AuthenticateResult == UserOperationsReference.DirectoryServicesEnumsUserProperties.SUCCESS) { Dictionary<string, string[]> siteRoles = null; //get the role types and roles if (HttpContext.Application["UISiteRoles"] != null) siteRoles = HttpContext.Application.GetApplicationState<Dictionary<string, string[]>>("UISiteRoles"); string groupResponseError = string.Empty; if (siteRoles != null && siteRoles.Count > 0) { //get the user roles from the AD service var groupsReq = new UserOperationsReference.GetUsersGroupsRequest(); groupsReq.userName = username; //execute the service method for getting the roles/groups var groupsResponse = adClient.GetUsersGroups(groupsReq); //retrieve the results if (groupsResponse != null) { groupResponseError = groupsResponse.errorMessage; var adRoles = groupsResponse.GetUsersGroupsResult; if (adRoles != null) { //loop through the roles returned from the server foreach (var adRole in adRoles) { //look for an admin role first foreach (var roleName in siteRoles.Keys) { var roles = siteRoles[roleName].ToList(); foreach (var role in roles) { if (adRole.Equals(role, StringComparison.InvariantCultureIgnoreCase)) { //we found a role, stop looking verifiedRoles += roleName + ";"; break; } } } } } } } if (String.IsNullOrEmpty(verifiedRoles)) { //no valid role we need to inform the user return View("Login", new object[] { "NO_ACCESS_ROLE", groupResponseError }); } if (verifiedRoles.EndsWith(";")) verifiedRoles = verifiedRoles.Remove(verifiedRoles.Length - 1, 1); //all is authenticated not build the auth ticket var authTicket = new FormsAuthenticationTicket( 1, // version username, // user name DateTime.Now, // created DateTime.Now.AddMinutes(20), // expires true, // persistent? verifiedRoles // can be used to store roles ); //encrypt the ticket before adding it to the http response string encryptedTicket = FormsAuthentication.Encrypt(authTicket); var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); Response.Cookies.Add(authCookie); Session["UserRoles"] = verifiedRoles.Split(';'); //redirect to calling page Response.Redirect(Session["LoginReturnURL"].ToString()); } else { retVal = View("Login", new object[] { authResponse.AuthenticateResult.ToString(), authResponse.errorMessage }); } return retVal; } } 

}

User authenticates, now create a new Identity

 protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e) { if (FormsAuthentication.CookiesSupported == true) { HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName]; if (authCookie == null || authCookie.Value == "") return; FormsAuthenticationTicket authTicket = null; try { authTicket = FormsAuthentication.Decrypt(authCookie.Value); } catch { return; } // retrieve roles from UserData if (authTicket.UserData == null) return; //get username from ticket string username = authTicket.Name; Context.User = new GenericPrincipal( new System.Security.Principal.GenericIdentity(username, "MyCustomAuthTypeName"), authTicket.UserData.Split(';')); } } 

On my site at the top of my _Layout.cshtml I have something like this

  { bool authedUser = false; if (User != null && User.Identity.AuthenticationType == "MyCustomAuthTypeName" && User.Identity.IsAuthenticated) { authedUser = true; } } 

Then in the body

  @{ if (authedUser) { <span id="loggedIn_userName"> <label>User Logged In: </label>@User.Identity.Name.ToUpper() </span> } else { <span id="loggedIn_userName_none"> <label>No User Logged In</label> </span> } } 
+4
Apr 04 '13 at 16:37
source share

Add users to the users in roles table. Use the addusertorole stored procedure (something like that) in your code to add to various roles. You can create roles very simply in the "roles" table.

Your tables to use: User, UsersInRole, Roles

Use the built-in stored procedures to manage these tables. Then all you have to do is add the attribute.

For example, you can have the “Admin” attribute in a view that selects a user and adds him to the role. You can use the stored proc to add this user to the role.

0
Sep 06 '09 at 14:48
source share
 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; using SISWEBBSI.Models.Model; using SISWEBBSI.Models.Model.Entities; using SISWEBBSI.Models.ViewModel; namespace SISWEBBSI.Controllers.ActionFilter { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] public sealed class RequerAutorizacao : ActionFilterAttribute { public Grupo.Papeis[] Papeis = {} ; public string ViewName { get; set; } public ViewDataDictionary ViewDataDictionary { get; set; } public AcessoNegadoViewModel AcessoNegadoViewModel { get; set; } public override void OnActionExecuting(ActionExecutingContext FilterContext) { if (!FilterContext.HttpContext.User.Identity.IsAuthenticated) { string UrlSucesso = FilterContext.HttpContext.Request.Url.AbsolutePath; string UrlRedirecionar = string.Format("?ReturnUrl={0}", UrlSucesso); string UrlLogin = FormsAuthentication.LoginUrl + UrlRedirecionar; FilterContext.HttpContext.Response.Redirect(UrlLogin, true); } else { if (Papeis.Length > 0) { //Papel ADMINISTRADOR sempre terá acesso quando alguma restrição de papeis for colocada. int NovoTamanho = Papeis.Count() + 1; Array.Resize(ref Papeis, NovoTamanho); Papeis[NovoTamanho - 1] = Grupo.Papeis.ADMINISTRADOR; UsuarioModel Model = new UsuarioModel(); if (!Model.UsuarioExecutaPapel(FilterContext.HttpContext.User.Identity.Name, Papeis)) { ViewName = "AcessoNegado"; String Mensagem = "Você não possui privilégios suficientes para essa operação. Você deve estar nos grupos que possuem"; if(Papeis.Length == 1) { Mensagem = Mensagem + " o papel: <BR/>"; } else if (Papeis.Length > 1) { Mensagem = Mensagem + " os papéis: <BR/>"; } foreach (var papel in Papeis) { Mensagem = Mensagem + papel.ToString() + "<br/>"; } AcessoNegadoViewModel = new AcessoNegadoViewModel(); AcessoNegadoViewModel.Mensagem = Mensagem; ViewDataDictionary = new ViewDataDictionary(AcessoNegadoViewModel); FilterContext.Result = new ViewResult { ViewName = ViewName, ViewData = ViewDataDictionary }; return; } } } } } } 
-9
Apr 08 '10 at 13:14
source share



All Articles