惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Cisco Talos Blog
Cisco Talos Blog
T
Threat Research - Cisco Blogs
P
Privacy International News Feed
S
Schneier on Security
P
Privacy & Cybersecurity Law Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
Scott Helme
Scott Helme
人人都是产品经理
人人都是产品经理
G
GRAHAM CLULEY
O
OpenAI News
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
PCI Perspectives
PCI Perspectives
GbyAI
GbyAI
宝玉的分享
宝玉的分享
Y
Y Combinator Blog
T
Troy Hunt's Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
腾讯CDC
C
Check Point Blog
Spread Privacy
Spread Privacy
L
LINUX DO - 最新话题
Recent Announcements
Recent Announcements
大猫的无限游戏
大猫的无限游戏
P
Palo Alto Networks Blog
Hacker News: Ask HN
Hacker News: Ask HN
M
MIT News - Artificial intelligence
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The Hacker News
The Hacker News
H
Hacker News: Front Page
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
T
Tor Project blog
Martin Fowler
Martin Fowler
博客园 - 叶小钗
罗磊的独立博客
C
Cyber Attacks, Cyber Crime and Cyber Security
H
Heimdal Security Blog
V
Vulnerabilities – Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
Latest news
Latest news
WordPress大学
WordPress大学
G
Google Developers Blog
N
Netflix TechBlog - Medium
S
Security Affairs
S
Secure Thoughts
Know Your Adversary
Know Your Adversary

博客园 - 君之蘭

WPF打印票据 easyui plugin——etreegrid:CRUD Treegrid 【经验谈】XmlSerializer的坑 从抽象谈起(三):AOP编程和ASP.NET MVC 从抽象谈起(二):观察者模式与回调 从抽象谈起(一):工厂模式与策略模式 SQL SERVER BI 入门:(2) Analysis Service 应用 SQL SERVER BI 入门:(1)安装与基础概念 HTML5 Canvas编写五彩连珠(6):试玩 HTML5 Canvas编写五彩连珠(5):寻路 HTML5 Canvas编写五彩连珠(4):动画 HTML5 Canvas编写五彩连珠(3):设计 HTML5 Canvas编写五彩连珠(2):画图 HTML5 Canvas编写五彩连珠(1):预览 Trie树-脏词过滤应用 带你走进缓存世界(6):共享缓存 ASP.NET MVC3 Custom ErrorPages 500/404 带你走进缓存世界(5):一显身手 带你走进缓存世界(4):缓存之缓
ASP.NET MVC3 Custom FormAuthorize
君之蘭 · 2011-10-19 · via 博客园 - 君之蘭

我们开发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>