ASP.NET MVC3 Custom FormAuthorize

我们开发web系统,用户身份验证是最常见不过的。最简单的办法就是定一个基类,基类里面有判断Cookie或Session是否存在,然后决定是否跳转。今天就利用MVC的特性来一个不一样的验证方式。

 

  1. public class CustomAuthorizeAttribute : AuthorizeAttribute  
  2. {  
  3.     protected override bool AuthorizeCore(HttpContextBase httpContext)  
  4.     {  
  5.         UserIdentity user = WebUtility.GetIdentity(httpContext);  
  6.         if (user != null)  
  7.         {  
  8.             httpContext.User = new UserPrincipal(WebUtility.GetIdentity(httpContext));  
  9.         }  
  10.   
  11.         return user != null;  
  12.     }  
  13.   
  14. }  

这是自定义的验证机制,重写了系统自带的验证核心逻辑,下面是系统自带的逻辑:

  1. protected virtual bool AuthorizeCore(HttpContextBase httpContext)  
  2. {  
  3.     if (httpContext == null)  
  4.     {  
  5.         throw new ArgumentNullException("httpContext");  
  6.     }  
  7.     IPrincipal user = httpContext.User;  
  8.     return user.Identity.IsAuthenticated && (this._usersSplit.Length <= 0 || this._usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)) && (this._rolesSplit.Length <= 0 || this._rolesSplit.Any(new Func<stringbool>(user.IsInRole)));  
  9. }  

可以看出,验证都是用httpContext.User属性来判断,所以我们对登录、退出和获取用户信息都通过httpContext.User属性就行了。从MVC的示例中我们也可以发现确实如此,看看MVC3的Views里的_LogOnPartial.cshtml的代码:

  1. @if(Request.IsAuthenticated) {  
  2.     <text>Welcome <strong>@User.Identity.Name</strong>!  
  3.     [ @Html.ActionLink("Log Off", "LogOff", "Account") ]</text>  
  4. }  
  5. else {  
  6.     @:[ @Html.ActionLink("Log On", "LogOn", "Account") ]  
  7. }  

那么现在再看我们刚才重写的验证逻辑,就大致明白了。首先通过一个外部的逻辑获取User,如果没有User说明没有登录,否则就给User赋值,标记登录了。
再看我们是如何获取这个User的

public static UserIdentity GetIdentity(HttpContextBase context)
{
	var user = GetUser(context);
	return new UserIdentity(user);
}

public static User GetUser(HttpContextBase httpContext)  
{  
    var user = httpContext.Request.Cookies[COOKIE_NAME_KEY];  //明文 比如用的userId
    var info = httpContext.Request.Cookies[COOKIE_INFO_KEY];  //密文
    if (user == null || info == null || !info.Value.DESDecrypt(DES_KEY).Contains(user.Value))  //解密后不一致,说明无效
    {  
        return null;  
    }  
  
    return new User{UserID = int.parse(user.value)};
}  


这就很易懂了,也是通过的cookie对用户资料做的存储。
httpContext.User是IPrincipal类型,所以我们要自定义一个UserPrincipal类:

 

public class UserPrincipal : IPrincipal
{
	public IIdentity Identity { get; private set; }

	public UserPrincipal(IIdentity identity)
	{
		this.Identity = identity;
	}

	public bool IsInRole(string role)
	{
		throw new NotSupportedException();
	}
}

似乎UserPrincipal并没有什么内容,而真证的数据存在Identity属性里,所以还需要定义一个UserIdentity类,来满足UserPrincipal。所以从最上面的代码可以看出WebUtility.GetIdentity(httpContext)返回的就是一个UserIdentity实例。

  1. public class UserIdentity : IIdentity  
  2. {  
  3.     public UserIdentity(User user)//此User就是从Cookie解密出来实例化的User
  4.     {  
  5.         User = user;  
  6.     }  
  7.   
  8.     public User User { getprivate set; }  
  9.   
  10.     public string Name  
  11.     {  
  12.         get { return User == null ? string.Empty : User.UserName; }  
  13.     }  
  14.   
  15.     public string AuthenticationType  
  16.     {  
  17.         get { return "maddemon"; }  
  18.     }  
  19.   
  20.     public bool IsAuthenticated  
  21.     {  
  22.         get { return User != null; }  
  23.     }  
  24. }  

好了,整个验证核心需要的东西我们都准备好了,还差一个最重要的东西就是我们登录的时候需要写cookie,退出的时候需要清除cookie。

  1. public static void SetAuthorizeCookie(HttpContextBase httpContext, User user)  
  2. {  
  3.     httpContext.Response.SetCookie(new HttpCookie(COOKIE_NAME_KEY, user.UserName));  
  4.     httpContext.Response.SetCookie(new HttpCookie(COOKIE_INFO_KEY, (user.UserName + "|" + user.Role).DESEncrypt(DES_KEY)));  
  5. }  
  6.   
  7. public static void RemoveAuthorizeCookie(HttpContextBase httpContext)  
  8. {  
  9.     httpContext.Response.SetCookie(new HttpCookie(COOKIE_NAME_KEY, null) { Expires = DateTime.Now.AddDays(-1) });  
  10.     httpContext.Response.SetCookie(new HttpCookie(COOKIE_INFO_KEY, null) { Expires = DateTime.Now.AddDays(-1) });  
  11. }  

这样一套下来,需要登录的Controller或Action,我们只需要加上一个[CustomAuthorize]属性就可以,如果没有登录就会自动跳转到config里配置的登录页。是不是很不方便啊? 方便吗?不方便吗? 方便吗?不方便吗? 方便吗?不方便吗?是不是啊 哈哈

  1. <authentication mode="Forms">  
  2.   <forms loginUrl="~/Account/LogOn" timeout="2880" />  
  3. </authentication>  
发布了42 篇原创文章 · 获赞 191 · 访问量 18万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章