asp.net-mvc ASP.NET MVC 表单身份验证 + 授权属性 + 简单角色
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1385042/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC Forms Authentication + Authorize Attribute + Simple Roles
提问by Kevin
I'm trying to add simpleAuthentication and Authorization to an ASP.NET MVC application.
我正在尝试向ASP.NET MVC 应用程序添加简单的身份验证和授权。
I'm just trying to tack on some added functionality to the basic Forms Authentication (due to simplicity and custom database structure)
我只是想在基本的表单身份验证中添加一些附加功能(由于简单和自定义数据库结构)
Assuming this is my database structure: User: username password role (ideally some enum. Strings if need be. Currently, user only has ONE role, but this might 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 determine links to display in some partials)
- 使用表单身份验证的简单登录
- 装饰我的动作:[Authorize(Roles={ MyRoles.Admin, MyRoles.Member})]
- 在我的视图中使用角色(以确定要在某些部分中显示的链接)
Currently, all I'm really sure of is how to Authenticate. After that I'm lost. I'm not sure at which point do I grab the user role (login, every authorization?). Since my roles may not be strings, I'm not sure how they will fit in with the User.IsInRole().
目前,我真正确定的是如何进行身份验证。在那之后我迷路了。我不确定在哪一点获取用户角色(登录、每次授权?)。由于我的角色可能不是字符串,我不确定它们将如何适应 User.IsInRole()。
Now, I'm asking here because I haven't found a "simple" accomplish what I need. I have seen multiple examples.
现在,我在这里问是因为我还没有找到一个“简单”的方法来完成我所需要的。我见过很多例子。
For Authentication:
对于身份验证:
- We have simple user validation that checks the database and "SetAuthCookie"
- Or we override the Membership provider and do this inside of ValidateUser In either of these, I'm not sure how to tack on my simple user Roles, so that they work with the: HttpContext.Current.User.IsInRole("Administrator") Furthermore, I'm not sure how to modify this to work with my enum values.
- 我们有简单的用户验证来检查数据库和“SetAuthCookie”
- 或者我们覆盖 Membership 提供程序并在 ValidateUser 中执行此操作在其中任何一个中,我不确定如何添加我的简单用户角色,以便它们使用: HttpContext.Current.User.IsInRole("Administrator")此外,我不确定如何修改它以使用我的枚举值。
For Authorization, I've seen:
对于授权,我见过:
- Deriving AuthorizeAttribute and implementing AuthorizeCore OR OnAuthorization to handle roles?
- Implementing IPrincipal?
- 派生 AuthorizeAttribute 并实施 AuthorizeCore 或 OnAuthorization 来处理角色?
- 实施IPrincipal?
Any assistance would be greatly appreciated. However, I fear I may need a lot of detail, because none of what I've Googled seems to fit with what I need to do.
任何帮助将不胜感激。但是,我担心我可能需要很多细节,因为我在 Google 上搜索的内容似乎都不适合我需要做的事情。
采纳答案by Neal
Build a custom AuthorizeAttributethat can use your enums rather than strings. When you need to authorise, convert the enums into strings by appending the enum type name + the enum value and use the IsInRolefrom there.
构建AuthorizeAttribute可以使用您的枚举而不是字符串的自定义。当您需要授权时,通过附加枚举类型名称 + 枚举值将枚举转换为字符串,并IsInRole从那里使用。
To add roles into an authorised user you need to attach to the HttpApplicationAuthenticateRequestevent something like the first code in http://www.eggheadcafe.com/articles/20020906.asp( but invert the massively nested if statements into guard clauses!).
要将角色添加到授权用户中,您需要将HttpApplicationAuthenticateRequest类似于http://www.eggheadcafe.com/articles/20020906.asp 中的第一个代码的内容附加到事件(但将大量嵌套的 if 语句反转为保护子句!)。
You can round-trip the users roles in the forms auth cookie or grab them from the database each time.
您可以在表单 auth cookie 中来回访问用户角色,也可以每次从数据库中获取它们。
回答by yinner
I think I've implemented something similar.
My solution, based on NerdDinnertutorial, is following.
我想我已经实现了类似的东西。
我的解决方案基于NerdDinner教程,如下所示。
When you sign the user in, add code like this:
当您登录用户时,添加如下代码:
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 following code to Global.asax.cs:
将以下代码添加到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 you've done this, you can use [Authorize]attribute in your controller action code:
完成此操作后,您可以在控制器操作代码中使用[Authorize]属性:
[Authorize(Roles="Admin")]
public ActionResult AdminIndex ()
Please let me know if you have further questions.
如果您还有其他问题,请告诉我。
回答by dynamiclynk
I did something like this:
我做了这样的事情:
- Use the Global.asax.cs to load the roles you want to compare in session,cache, or application state, or load them on the fly on the ValidateUser controller
- 使用 Global.asax.cs 加载要在会话、缓存或应用程序状态中比较的角色,或在 ValidateUser 控制器上动态加载它们
Assign the [Authorize] attribute to your controllers, you want to require authorization for
将 [Authorize] 属性分配给您的控制器,您需要授权
[Authorize(Roles = "Admin,Tech")]
or to allow access, for example the Login and ValidateUser controllers use the below attribute
或允许访问,例如 Login 和 ValidateUser 控制器使用以下属性
[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 invoked from the Form post
从表单帖子调用的登录控制器和验证用户控制器
Validate user is authentication via a WCF service that validates against the Windows AD Context local to the service, but you can change this to your own authentication mechanism
验证用户通过 WCF 服务进行身份验证,该服务针对服务本地的 Windows AD 上下文进行验证,但您可以将其更改为您自己的身份验证机制
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 is authenticated now create the 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 the top of my _Layout.cshtml I have something like this
在我的 _Layout.cshtml 顶部的网站上,我有这样的东西
{
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>
}
}
回答by dynamiclynk
Add your users to the table "users in roles". Use the stored procedure "addusertorole" (something like that) in your code to add to various roles. You can create the roles very simply in the "roles" table.
将您的用户添加到“角色中的用户”表中。在您的代码中使用存储过程“addusertorole”(类似的东西)来添加到各种角色。您可以在“角色”表中非常简单地创建角色。
Your tables to use: User, UsersInRole, Roles
要使用的表:User、UsersInRole、Roles
Use the built in Stored Procs to manipulate those tables. Then all you have to do is add the attribute.
使用内置的存储过程来操作这些表。然后你所要做的就是添加属性。
For example you can have an "Admin" attribute on a view that selects a user and adds them to a role. You can use the stored proc to add that user to the role.
例如,您可以在选择用户并将其添加到角色的视图上使用“管理员”属性。您可以使用存储过程将该用户添加到角色。
回答by Marlon
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;
}
}
}
}
}
}

