ASP.NET MVC表单身份validation+授权属性+简单angular色

我试图添加简单的身份validation和授权到ASP.NET MVC应用程序。

我只是试图添加一些基本的表单身份validationfunction(由于简单和自定义数据库结构)

假设这是我的数据库结构:用户:用户名密码angular色(理想情况下是一些枚举,如果需要的话,string。目前,用户只有一个angular色,但这可能会改变)

高层次的问题:鉴于上述数据库结构,我希望能够做到以下几点:

  • 使用表单身份validation简单login
  • 装饰我的行动:[授权(angular色= {MyRoles.Admin,MyRoles.Member})]
  • 在我的视图中使用angular色(确定在某些部分显示的链接)

目前,我真的很确定的是如何进行身份validation。 之后,我迷路了。 我不知道我在哪一点抓住用户angular色(login,每个授权?)。 由于我的angular色可能不是string,我不知道他们将如何适应与User.IsInRole()。

现在,我在这里问,因为我没有find一个“简单”完成我所需要的。 我看过很多例子。

对于authentication:

  • 我们有简单的用户validation来检查数据库和“SetAuthCookie”
  • 或者我们重写成员提供程序,并在ValidateUser中执行此操作在这两者中,我不确定如何处理我的简单用户angular色,以便它们可以使用:HttpContext.Current.User.IsInRole(“Administrator”)此外,我不知道如何修改这个来处理我的枚举值。

对于授权,我已经看到:

  • 派生AuthorizeAttribute并实现AuthorizeCore或OnAuthorization来处理angular色?
  • 实施IPrincipal?

任何援助将不胜感激。 不过,我担心我可能需要很多细节,因为我没有使用谷歌search似乎符合我需要做的。

构build一个可以使用枚举而不是string的自定义AuthorizeAttribute 。 当需要授权时,通过附加枚举types名称和枚举值将enums转换为string,并从那里使用IsInRole

要将angular色添加到授权用户,您需要附加到HttpApplication AuthenticateRequest事件,类似于http://www.eggheadcafe.com/articles/20020906.asp中的第一个代码(但将大量嵌套的if语句转换为guard子句!); 。

您可以将表单auth cookie中的用户angular色进行往返,也可以每次从数据库中抓取用户angular色。

我想我已经实现了类似的东西。
基于NerdDinner 教程的我的解决scheme如下。

当你签入用户时 ,添加如下代码:

 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); HttpContext.Current.Response.Cookies.Add(authCookie); 

将以下代码添加到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); } 

完成此操作后,可以在控制器操作代码中使用[Authorize]属性:

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

如果您还有其他问题,请告诉我。

我做了这样的事情:

  • 使用Global.asax.cs加载要在会话,高速caching或应用程序状态中比较的angular色,或者在ValidateUser控制器上实时加载它们

为您的控制器分配[授权]属性,您想要授权

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

或允许访问,例如Login和ValidateUser控制器使用下面的属性

  [AllowAnonymous] 

我的login表单

 <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控制器和ValidateUser控制器调用从窗体post

validation用户是通过WCF服务进行validation,该服务可以针对服务本地的Windows AD Context进行validation,但是您可以将其更改为您自己的validation机制

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

}

用户现在通过身份validation创build新的身份

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

在我的_Layout.cshtml顶部我的网站上,我有这样的事情

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

然后在身体

  @{ 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> } } 

将您的用户添加到“angular色中的用户”表中。 在代码中使用存储过程“addusertorole”(类似的东西)来添加到各种angular色。 您可以非常简单地在“angular色”表中创buildangular色。

您要使用的表格:User,UsersInRole,Roles

使用内置的存储过程来操作这些表。 那么你所要做的就是添加属性。

例如,您可以在视图上具有“Admin”属性,以select用户并将其添加到angular色。 您可以使用存储的proc将该用户添加到该angular色。

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