ASP.NET MVC3 Custom FormAuthorize
我们开发web系统,用户身份验证是最常见不过的。最简单的办法就是定一个基类,基类里面有判断Cookie或Session是否存在,然后决定是否跳转。今天就利用MVC的特性来一个不一样的验证方式。
- public class CustomAuthorizeAttribute : AuthorizeAttribute
 - {
 - protected override bool AuthorizeCore(HttpContextBase httpContext)
 - {
 - UserIdentity user = WebUtility.GetIdentity(httpContext);
 - if (user != null)
 - {
 - httpContext.User = new UserPrincipal(WebUtility.GetIdentity(httpContext));
 - }
 - return user != null;
 - }
 - }
 
这是自定义的验证机制,重写了系统自带的验证核心逻辑,下面是系统自带的逻辑:
- protected virtual bool AuthorizeCore(HttpContextBase httpContext)
 - {
 - if (httpContext == null)
 - {
 - throw new ArgumentNullException("httpContext");
 - }
 - IPrincipal user = httpContext.User;
 - 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<string, bool>(user.IsInRole)));
 - }
 
可以看出,验证都是用httpContext.User属性来判断,所以我们对登录、退出和获取用户信息都通过httpContext.User属性就行了。从MVC的示例中我们也可以发现确实如此,看看MVC3的Views里的_LogOnPartial.cshtml的代码:
- @if(Request.IsAuthenticated) {
 - <text>Welcome <strong>@User.Identity.Name</strong>!
 - [ @Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
 - }
 - else {
 - @:[ @Html.ActionLink("Log On", "LogOn", "Account") ]
 - }
 
那么现在再看我们刚才重写的验证逻辑,就大致明白了。首先通过一个外部的逻辑获取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实例。
- public class UserIdentity : IIdentity
 - {
 - public UserIdentity(User user)//此User就是从Cookie解密出来实例化的User
 - {
 - User = user;
 - }
 - public User User { get; private set; }
 - public string Name
 - {
 - get { return User == null ? string.Empty : User.UserName; }
 - }
 - public string AuthenticationType
 - {
 - get { return "maddemon"; }
 - }
 - public bool IsAuthenticated
 - {
 - get { return User != null; }
 - }
 - }
 
好了,整个验证核心需要的东西我们都准备好了,还差一个最重要的东西就是我们登录的时候需要写cookie,退出的时候需要清除cookie。
- public static void SetAuthorizeCookie(HttpContextBase httpContext, User user)
 - {
 - httpContext.Response.SetCookie(new HttpCookie(COOKIE_NAME_KEY, user.UserName));
 - httpContext.Response.SetCookie(new HttpCookie(COOKIE_INFO_KEY, (user.UserName + "|" + user.Role).DESEncrypt(DES_KEY)));
 - }
 - public static void RemoveAuthorizeCookie(HttpContextBase httpContext)
 - {
 - httpContext.Response.SetCookie(new HttpCookie(COOKIE_NAME_KEY, null) { Expires = DateTime.Now.AddDays(-1) });
 - httpContext.Response.SetCookie(new HttpCookie(COOKIE_INFO_KEY, null) { Expires = DateTime.Now.AddDays(-1) });
 - }
 
这样一套下来,需要登录的Controller或Action,我们只需要加上一个[CustomAuthorize]属性就可以,如果没有登录就会自动跳转到config里配置的登录页。是不是很不方便啊? 方便吗?不方便吗? 方便吗?不方便吗? 方便吗?不方便吗?是不是啊 哈哈
- <authentication mode="Forms">
 - <forms loginUrl="~/Account/LogOn" timeout="2880" />
 - </authentication>
 
                    
                
                
            
        
浙公网安备 33010602011771号