给Asp.net MVC Forms 验证设置角色访问控制

当我们使用Asp.net MVC Forms方式验证用户, 然后设置Controller 或 Action 的 Authorize属性时, 默认情况下只有Users属性可以设置(这里的Users通常是指用户登录名), 我们无法直接设置用户的角色信息 , 当建立一个依赖角色的应用时(又不想麻烦配置Membership),我们有必要给认证用户加上角色信息,下面是具体方法 :

1.Web.config 配置 ,以下设置标明我们使用Forms验证

    <authentication mode="Forms">
<forms loginUrl="~/Account/LogIn" timeout="" slidingExpiration="true" cookieless="UseCookies" path="/" name=".MYASPXAUTH" />
</authentication>
<!--<authorization>
<deny users="?"/>
</authorization>-->

具体配置参考:http://msdn.microsoft.com/zh-cn/library/1d3t3c61(v=vs.100).aspx

<forms
name="name"
loginUrl="URL"
defaultUrl="URL"
protection="[All|None|Encryption|Validation]"
timeout="[MM]"
path="path"
requireSSL="[true|false]"
slidingExpiration="[true|false]">
enableCrossAppRedirects="[true|false]"
cookieless="[UseUri|UseCookies|AutoDetect|UseDeviceProfile]"
domain="domain name"
ticketCompatibilityMode="[Framework20|Framework40]">
<credentials>...</credentials>
</forms>

slidingExpiration:是否滑动过期,应设置为true    
    name属性:如果服务器有多个应用程序,每个应用程序的name属性应不同。
    上面代码注释掉了deny 设置,如果设置了上面的项,则所有页面都需要用户登录。注释掉之后,只在访问在Controller或Action上面设置了验证用户或角色的页面时,才提示登录。
2 Global.asax.cs 添加验证请求事件代码 ,如果用户信息已经设置, 则重新构造带角色信息的用户对象 , 角色信息从身份凭证票据的UserData属性中获取,多个角色以逗号隔开。

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
var app = sender as HttpApplication; if (app.Context.User != null)
{
var user = app.Context.User;
var identity = user.Identity as FormsIdentity; // We could explicitly construct an Principal object with roles info using System.Security.Principal.GenericPrincipal
var principalWithRoles = new GenericPrincipal(identity, identity.Ticket.UserData.Split(',')); // Replace the user object
app.Context.User = principalWithRoles;
}
}

上面代码是Asp.net请求管道中的一个环节,每次请求时都会执行。
    如果UserData中还想保存其它数据,需要使用其它分隔符进行分割并处理。
    这种方式主要用于系统功能简单,角色较少的应用。
经过上面角色的转换,系统就可以直接使用内部定义的验证方式进行验证了。

给Asp.net MVC Forms 验证设置角色访问控制

3.用户合法性验证通过后, 构造带角色信息的加密身份凭据 , 角色信息存储在票据的UserData中。

[HttpPost]
public ActionResult LogOn(User user)
{
// check user by quering database or other ways. skip this logic. string userRoles = "admin,user,powerUser";
bool isPersistent = false;
int version = ;
double persistentMinutes = 30.00; // minutes
string userName = user.Name; string cookiePath = FormsAuthentication.FormsCookiePath; FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(version, userName, DateTime.Now, DateTime.Now.AddMinutes(persistentMinutes), isPersistent, userRoles, cookiePath);
string encryptedTicket = FormsAuthentication.Encrypt(ticket); HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(cookie); return Redirect(Request.QueryString["returnUrl"]);
}

isPersistent:是否将cookie持久化保存到客户端硬盘。一般应该选择false,即每次访问都要登录。但可以将用户名保存到客户端,用户登录时直接取得并设为默认。

HttpCookie userNmaecook=new HttpCookie("MyAppUserName",userName);
vljidcook.Expires=DateTime.Now.AddDays();
this.Context.Response.Cookies.Add(userNmaecook);

4. 使用角色信息控制用户对Controller 或 Action 的访问 , 因为我们上面设置用户拥有admin , user , powerUser 角色, 所以用户有权访问此方法

public class HomeController : Controller
{
[Authorize(Roles="admin,powerUser")]
public ActionResult Index()
{
//用户拥有 admin,user,powerUser 角色, 所以可以访问此方法。
return View();
}
}

一般权限应按ontroller设置,后台管理和前台浏览使用不同的controller。

5. 以下是AuthorizeAttribute AuthorizeCore方法的源码 , 我们可以看到其中只要用户有AuthorizeAttribute.Roles设置中的任意角色, 就可以通过AuthorizeAttribute 的审核

// This method must be thread-safe since it is called by the thread-safe OnCacheAuthorization() method.
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
} IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
} if (_usersSplit.Length > && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
} if (_rolesSplit.Length > && !_rolesSplit.Any(user.IsInRole))
{
return false;
} return true;
}
上一篇:分享一个牛逼的PHP无限极分类生成树方法,巧用引用(转)


下一篇:PHP使用引用实现无限极分类