1.前言
a.微軟對ASP.NET的開發從WebForm到MVC的轉變,已經正式過去5,6個年頭,現在WebForm和MVC也都越來越完善,小小算來我也已經工作了將近三年,從大學的時候學習ASP.NET WebForm,感覺這就是我們以后吃飯的技術,所以當時可勁的學習拖各種控件,學習做各種各樣的小項目,但是沒想到的是,從大學最后一學期參加實習開始到現在也就一直沒有機會接觸ASP.NET WebForm,基本也都是在用MVC開發。我並不是說MVC就比WebForm開發好或者什么的,我只是覺得他們都是工具,只要我們使用任何一種工具能夠順手,能給我們帶來更快速的開發和收獲,我們就可以去使用它。
b.那么MVC也同時給我們帶來了不一樣的開發體驗,它增加了很多的開發技巧和技術,比如:路由機制(Web Form也已加入),Razor引擎,特性(Attribute)等,隨着Visual Studio2015的發布,ASP.NET MVC6的跨平台也已經來到,那么說了這么多,我們今天主要的還是簡單說一下MVC的特性,我將這些經常用到的技術都給整理起來,等到我們后面有機會用到的時候直接將其拿出來使用即可。
c.源碼(Git)地址:https://github.com/kencery/Common/blob/master/KenceryCommonMethod/AuthorizeAttribute/LoginAttribute.cs
2.AuthorizeAttribute登錄特性解釋
a.在項目開發中,通常我們都會涉及到用戶登錄才能訪問的網頁,比如購物網站,我們瀏覽商品,添加購物車(以前開發的時候在這里就需要登錄用戶,但是現在有了緩存的實現,這里可以將商品加入緩存,等到結賬的時候在登錄)選擇結賬的時候需要登錄,那么這時候我們需要跳轉到登錄頁面登錄,登錄之后還可以回到記錄下來的原始的頁面,那么這之后我們有好幾種方法可以實現這種效果,簡單舉例:
(1):第一種:登錄模塊不管怎么樣都是統一的,就是在每個需要登錄的方法里面判斷用戶是否登錄,如果沒有登錄,則跳轉登錄,這種的缺點是工作量大,代碼冗余。
(2):第二種:使用MVC的特性,定義類繼承IAuthorizationFilter,重寫OnAuthorization方法即可實現。此方法工作量少,代碼不冗余,如果需要登錄我們只需要給Controller或者Action給上標簽即可。
b.任何能夠使用特性的判斷都可以按照下面的思路來實現,例如(登錄判斷,權限判斷,請求判斷,去除空格,讀取返回路徑)等等,在項目中又遇到這些方方面面需要在請求發起之前或者請求發起之后訪問的,都可以實現特性去實現。
c.下面是我簡單整理的的a中說的這種需要的特性實現,代碼示例如下,請查看:
3.代碼示例
a.下面我簡單說一下這個實現的思路,如果大家有什么意見可以在底下留言,純屬於整理,沒多少技術含量,請大家見諒,如果代碼不能實現你們的需求,請按照你們的需求更改即可實現。
(1).首先定義類繼承自FilterAttribute, IAuthorizationFilter,會讓你實現重寫OnAuthorization方法。
(2).從web.Config中存放三個常量(登錄地址,登錄Session或Cookie鍵,Session或者Cookie登錄的判斷),在構造函數中讀取Web.Config中的信息,實現構造函數。
(3).重寫OnAuthorization方法,判斷是Cookie或者Session記錄用戶登錄信息,然后判斷Session或者Cookie是否為空,如果為空,則登錄至指定的地址,否則退出即可。
(4).使用,如果Controller或者Action需要判斷是否登錄,則打上特性[Login],否則不需要,如果在某一個Controller中,大部分方法需要,只有一兩個不需要,在Controller中打上特性[Login],在不需要的方法上打上特性[AllowAnonymous]即可實現。
b.上面說了這么多,基本都是一些思路,實現代碼示例如下,請查看:
1 // 源文件頭信息: 2 // <copyright file="LoginAttribute.cs"> 3 // Copyright(c)2014-2034 Kencery.All rights reserved. 4 // 個人博客:http://www.cnblogs.com/hanyinglong 5 // 創建人:韓迎龍(kencery) 6 // 創建時間:2015-8-7 7 // </copyright> 8 9 using System; 10 using System.Web; 11 using System.Web.Mvc; 12 using System.Web.UI.WebControls; 13 14 namespace KenceryCommonMethod 15 { 16 /// <summary> 17 /// 添加此特性的功能是:需要用戶登錄才能夠瀏覽網頁,如果不需要用戶登錄,則可以使用AllowAnonymousAttribute屬性 18 /// 使用:給ASP.NET MVC中的控制器類名或者Action方法上面打上[Login]標簽 19 /// 如果不需要驗證用戶是否登錄就可以瀏覽,則給ASP.NET MVC中的控制器類名或者Action方法上面打上[AllowAnonymous]標簽 20 /// </summary> 21 /// <auther> 22 /// <name>Kencery</name> 23 /// <date>2015-8-7</date> 24 /// </auther> 25 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)] 26 public class LoginAttribute : FilterAttribute, IAuthorizationFilter 27 { 28 /// <summary> 29 /// 該值表示登錄地址:默認路徑為user/login,在Web.Config中設置 30 /// </summary> 31 private string _authUrl = string.Empty; 32 33 public string AuthUrl 34 { 35 get 36 { 37 return _authUrl.Trim(); 38 } 39 set 40 { 41 if (string.IsNullOrEmpty(value)) 42 { 43 throw new ArgumentNullException("AuthUrl為空,驗證用戶登錄信息的用戶登錄地址不能為空"); 44 } 45 _authUrl = value.Trim(); 46 } 47 } 48 49 /// <summary> 50 /// 該值表示yoghurt登錄保存登錄信息的鍵名,默認user,在web.Config中設置 51 /// </summary> 52 private string _authSaveKey = string.Empty; 53 54 public string AuthSaveKey 55 { 56 get { return _authSaveKey.Trim(); } 57 set 58 { 59 if (string.IsNullOrEmpty(value)) 60 { 61 throw new ArgumentNullException("AuthSaveKey為空,驗證用戶登錄的時候保存的登錄鍵信息不能為空"); 62 } 63 _authSaveKey = value.Trim(); 64 } 65 } 66 67 /// <summary> 68 /// 該值表示用戶登錄保存登錄信息的類型,默認Session,在web.Config中設置 69 /// </summary> 70 private string _authSaveType = string.Empty; 71 72 public string AuthSaveType 73 { 74 get { return _authSaveType.Trim().ToUpper(); } 75 set 76 { 77 if (string.IsNullOrEmpty(value)) 78 { 79 throw new ArgumentNullException("AuthSaveType為空,驗證用戶登錄的時候未保存鍵信息類型,類型不能為空"); 80 } 81 _authSaveType = value.Trim().ToUpper(); 82 } 83 } 84 85 /// <summary> 86 /// 默認構造函數 87 /// </summary> 88 public LoginAttribute() 89 { 90 const string authUrl = "/User/Index"; //登錄頁面路徑,從Web.Config中讀取 91 const string saveKey = "user"; //驗證(登錄存放用戶信息),從Web.Config中讀取 92 const string saveType = "Session"; //存放類型判斷(Session或者Cookie存放),,從Web.Config中讀取 93 _authUrl = string.IsNullOrEmpty(authUrl) ? "/User/Index" : authUrl; 94 95 } 96 97 /// <summary> 98 /// 構造函數重載 99 /// </summary> 100 /// <param name="authUrl"></param> 101 public LoginAttribute(string authUrl) : this() 102 { 103 _authUrl = authUrl; 104 } 105 106 /// <summary> 107 /// 構造函數重載 108 /// </summary> 109 /// <param name="authUrl"></param> 110 /// <param name="saveKey"></param> 111 public LoginAttribute(string authUrl, string saveKey) : this(authUrl) 112 { 113 _authSaveKey = saveKey; 114 _authSaveType = "Session"; 115 } 116 117 /// <summary> 118 /// 構造函數重載 119 /// </summary> 120 /// <param name="authUrl"></param> 121 /// <param name="saveKey"></param> 122 /// <param name="saveType"></param> 123 public LoginAttribute(string authUrl, string saveKey, string saveType) : this(authUrl, saveKey) 124 { 125 _authSaveType = saveType; 126 } 127 128 public void OnAuthorization(AuthorizationContext filterContext) 129 { 130 if (filterContext.HttpContext == null) 131 { 132 throw new Exception("此特性只試用於Web應用程序試用"); 133 } 134 var flAd = filterContext.ActionDescriptor; 135 var url = string.Format("{0}?Ref=/{1}/{2}", _authUrl, flAd.ControllerDescriptor.ControllerName, 136 flAd.ActionName); 137 switch (AuthSaveType) 138 { 139 case "SESSION": 140 if (filterContext.HttpContext.Session == null) 141 { 142 throw new Exception("服務器Session不可用"); 143 } 144 if (!filterContext.ActionDescriptor.IsDefined(typeof (AllowAnonymousAttribute), true) && 145 !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined( 146 typeof (AllowAnonymousAttribute), true)) 147 { 148 if (filterContext.HttpContext.Session[_authSaveKey] == null) 149 { 150 filterContext.Result = new RedirectResult(url); 151 } 152 } 153 break; 154 case "COOKIE": 155 if (!filterContext.ActionDescriptor.IsDefined(typeof (AllowAnonymousAttribute), true) && 156 !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined( 157 typeof (AllowAnonymousAttribute), true)) 158 { 159 if (filterContext.HttpContext.Request.Cookies[_authSaveKey] == null) 160 { 161 filterContext.Result = new RedirectResult(url); 162 } 163 } 164 break; 165 default: 166 throw new ArgumentNullException("用戶保存登錄信息的方法不能為空,只能為Cookie和Session,請您檢查"); 167 } 168 } 169 } 170 }