Asp.net mvc 4 将角色与表单身份验证一起使用
我在MVC应用程序中使用表单身份验证。这很好用。但我不想调整授权,只允许某些角色的人。登录名对应于active directory中的用户,角色对应于用户所在的组 对于身份验证,我只需在验证登录后调用FormsAuthentication.SetAuthCookie(用户名,true) 为了进行授权,我首先将该属性应用于要保护的控制器Asp.net mvc 4 将角色与表单身份验证一起使用,asp.net-mvc-4,authorization,forms-authentication,Asp.net Mvc 4,Authorization,Forms Authentication,我在MVC应用程序中使用表单身份验证。这很好用。但我不想调整授权,只允许某些角色的人。登录名对应于active directory中的用户,角色对应于用户所在的组 对于身份验证,我只需在验证登录后调用FormsAuthentication.SetAuthCookie(用户名,true) 为了进行授权,我首先将该属性应用于要保护的控制器 [Authorize(Roles = "AllowedUsers")] public class MyController ... 接下来,我将在global.
[Authorize(Roles = "AllowedUsers")]
public class MyController
...
接下来,我将在global.asax中处理OnAuthenticate事件
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs args)
{
if (FormsAuthentication.CookiesSupported)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
Request.Cookies[FormsAuthentication.FormsCookieName].Value);
// Create WindowsPrincipal from username. This adds active directory
// group memberships as roles to the user.
args.User = new WindowsPrincipal(new WindowsIdentity(ticket.Name));
FormsAuthentication.SetAuthCookie(ticket.Name, true);
}
catch (Exception e)
{
// Decrypt method failed.
}
}
}
else
{
throw new HttpException("Cookieless Forms Authentication is not " + "supported for this application.");
}
}
当有人访问网站时,他们会看到登录屏幕。他们实际上可以从那里登录。然而,不知何故,它并没有保存auth cookie,他们在单击下一个链接后会看到一个登录屏幕。我尝试在OnAuthenticate()中添加对SetAuthCookie()的调用,但没有效果
在我添加此事件处理程序来处理授权之前,身份验证工作正常。因此,框架中的某个地方正在设置用户。我想知道这是否是正确的方法,我只是错过了一些东西,或者我是否需要一个不同的方法
我需要做些什么才能让它工作
谢谢,
Scott角色也可以存储在cookie中,您至少有两个选项:
- 角色提供程序cookie(另一个支持表单cookie的cookie),在
中的角色提供程序配置上设置为web.config
。授权模块第一次请求角色时读取角色,然后发出cookiecacheRolesInCookie=“true”
- 在表单cookie的userdata部分中存储角色的自定义角色提供程序,必须手动将角色添加到表单cookie的user data部分
授权
模块向当前主体询问用户角色,如果启用了角色提供程序,则会扫描角色cookie(第一个选项)或触发自定义角色提供程序方法
另一种推荐的方法是切换到会话身份验证模块(SAM),它可以替代表单身份验证。有一些重要的优点,包括SAM从cookie中重新创建ClaimsPrincipal
,角色只是Role
声明:
// create cookie
SessionAuthenticationModule sam =
(SessionAuthenticationModule)
this.Context.ApplicationInstance.Modules["SessionAuthenticationModule"];
ClaimsPrincipal principal =
new ClaimsPrincipal( new GenericPrincipal( new GenericIdentity( "username" ), null ) );
// create any userdata you want. by creating custom types of claims you can have
// an arbitrary number of your own types of custom data
principal.Identities[0].Claims.Add( new Claim( ClaimTypes.Role, "role1" ) );
principal.Identities[0].Claims.Add( new Claim( ClaimTypes.Role, "role2" ) );
var token =
sam.CreateSessionSecurityToken(
principal, null, DateTime.Now, DateTime.Now.AddMinutes( 20 ), false );
sam.WriteSessionTokenToCookie( token );
从现在起,身份将存储在cookie中并自动管理,是的,控制器上的Authorization
属性将按预期工作
在我的博客上阅读有关用SAM替换表单模块的更多信息:
看来我最初的方法行不通。我试图让ASP.NET自动从他们的广告帐户加载用户角色。没有就这是否可能发表评论。然而,我所做的研究表明,我必须编写代码将广告组成员身份加载到用户角色中 创建ASP.NET MVC使用的用户主体的解决方案似乎是在FormsAuthentication_OnAuthenticate()中创建它,并将其分配给Context.user。如果未设置上下文,则会出现此错误。用户ASP.NET MVC在FormsAuthentication_OnAuthenticate()返回后,根据身份验证票证创建用户主体。此外,如果我在FormsAuthentication_onAuthentication()中设置了Context.User,则ASP.NET MVC似乎与Context.User无关 下面是我最后做的事情 这是处理身份验证的代码
public ActionResult LogOn(FormCollection collection, string returnUrl)
{
// Code that authenticates user against active directory
if (authenticated)
{
var authTicket = new FormsAuthenticationTicket(username, true, 20);
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.Expires = DateTime.Now.AddMinutes(30);
Response.Cookies.Add(authCookie);
if (Url.IsLocalUrl(returnUrl)
&& returnUrl.Length > 1
&& returnUrl.StartsWith("/", StringComparison.OrdinalIgnoreCase)
&& !returnUrl.StartsWith("//", StringComparison.OrdinalIgnoreCase)
&& !returnUrl.StartsWith("/\\", StringComparison.OrdinalIgnoreCase))
{
return Redirect(returnUrl);
}
else
{
return Redirect("~/");
}
}
return View();
}
我最初尝试调用FormsAuthentication.SetAuthCookie(用户名,true),而不是手动创建、加密并将其添加到响应cookie集合中。这在开发环境中起了作用。然而,在我把它发布到网站上之后,它就没有了
这是注销代码
public ActionResult LogOff()
{
var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
authCookie.Expires = DateTime.Today.AddDays(-1);
}
Response.Cookies.Add(authCookie);
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Home");
}
在我切换到手动创建、加密并将身份验证票证添加到登录代码中的响应cookie集合之后,FormsAuthentication.SignOut()似乎没有做任何事情。所以我不得不手动使cookie过期
这是我用于FormsAuthentication_OnAuthenticate()的代码
UserData是我创建的一个类,用于处理缓存用户角色。这是必需的,因为active directory返回用户所属的组成员身份需要时间。为了完整起见,下面是我为UserData编写的代码
public class UserData
{
private int _TimeoutInMinutes;
private string[] _Roles = null;
public string UserName { get; private set; }
public DateTime Expires { get; private set; }
public bool Expired { get { return Expires < DateTime.Now; } }
public string[] Roles
{
get
{
if (Expired || _Roles == null)
{
_Roles = GetADContainingGroups(UserName).ToArray();
Expires = DateTime.Now.AddMinutes(_TimeoutInMinutes);
}
return _Roles;
}
}
public UserData(string userName, int timeoutInMinutes = 20)
{
UserName = userName;
_TimeoutInMinutes = timeoutInMinutes;
}
}
公共类用户数据
{
私用整数分钟;
私有字符串[]_Roles=null;
公共字符串用户名{get;private set;}
公共日期时间过期{get;private set;}
public bool Expired{get{return Expires
您是否尝试转储当前用户所在的组/声明列表?我怀疑他们在那里,但作为广告组SID不是组名。很抱歉延迟响应。工作中出现了一些问题。总之,这是一个有趣的理想。但是,我不喜欢在cookie中缓存用户角色的想法。难道用户不可能修改cookies的内容并给自己任何他们想要的角色吗?ASP.NET身份验证Cookie是加密的,或者可能只是以64进制编码。所以这并不容易。我仍然认为我会将其缓存在应用程序变量或数据库中。这也将使POST/GET中发送的数据量最小化。身份验证cookie始终是加密的。
public class UserData
{
private int _TimeoutInMinutes;
private string[] _Roles = null;
public string UserName { get; private set; }
public DateTime Expires { get; private set; }
public bool Expired { get { return Expires < DateTime.Now; } }
public string[] Roles
{
get
{
if (Expired || _Roles == null)
{
_Roles = GetADContainingGroups(UserName).ToArray();
Expires = DateTime.Now.AddMinutes(_TimeoutInMinutes);
}
return _Roles;
}
}
public UserData(string userName, int timeoutInMinutes = 20)
{
UserName = userName;
_TimeoutInMinutes = timeoutInMinutes;
}
}