RouteExistingFiles 屬性
當用戶請求如圖片、視頻等靜態文件資源時,asp.net會很高興的定位文件位置並提供給用戶,除非我們做了某些限制。有時我們需要做一些限制只能讓所有者訪問而不能讓其他用戶訪問,一種簡單的情況是通過web.config 文件配置進行限制,但在複雜的情況下,如果能夠通過action/filter控制訪問權限將是不錯的選擇,爲了實現這個目的需要將靜態文件請求通過MVC pipeline 進行處理,而MVC的RouteExistingFiles屬性恰好能做到,通過將RouteExistingFiles屬性設置爲true,MVC將處理這些請求,而不是由iis處理這些靜態文件請求。
下面討論如何實現,例如:
下面是 Global.asax.cs文件
1
2
3
4
5
6
7
8
9
10
|
public static
void
RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" ); routes.MapRoute( "Default" , "{controller}/{action}/{id}" , new {
controller = "Home" ,
action = "Index" ,
id = UrlParameter.Optional } ); } |
設置RouteExistingFiles = true,禁止 IIS 處理這些存在的靜態文件請求併發送結果
1
2
3
4
5
6
7
|
public static
void
RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" ); routes.RouteExistingFiles
= true ; ... } |
下一步,需要定義一個新的路由處理這些情況,URL模式部分看起來比較象物理路徑,但不用如此,這裏只是個例子.
1
2
3
4
5
|
routes.MapRoute( "photo" , "premium/photos/{accountNo}/{image}" , new {
controller = "Photo" ,
action = "Index" } ); |
如你所想,我們需要新建controller和action ,index方法將返回請求的完整路徑.
1
2
3
4
5
6
7
|
public class
PhotoController : Controller { public FileResult
Index() { return File(Request.RawUrl,
"image/jpeg" ); } } |
但我們的index方法仍然不安全,需要添加驗證,通過自定義authorize 屬性 ,這個自定義屬性通過檢查url中的accountNo 和存在session的accountNo作對比,如果不匹配,則返回401
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public class
PhotoAuthorizeAttribute : AuthorizeAttribute { protected override
bool
AuthorizeCore(HttpContextBase httpContext) { if ( base .AuthorizeCore(httpContext)) { var
accountNo = httpContext.Request.RequestContext.RouteData.Values[ "accountNo" ]; if (accountNo
!= null &&
httpContext.Session[ "AccountNo" ].ToString()
== accountNo.ToString()) { return true ; } return false ; } return false ; } } |
我們需要給返回靜態文件資源的action加上自定義權限驗證屬性PhotoAuthorize attribute.
1
2
3
4
5
|
[PhotoAuthorize] public FileResult
Index() { return File(Request.RawUrl,
"image/jpeg" ); } |
但有一個重要的問題是,一旦把RouteExistingFiles屬性設置爲true,Content文件夾下的styles 和 javascript 的文文件同樣會被阻止,這是個大問題,這個屬性的影響是全局的,那如何發送這些css, js文件?爲它們單獨創建controller和action是個不好的方法,幸運的是還有IgnoreRoutemethod方法可以方便解決這個問題
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public static
void
RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute( "{resource}.axd/{*pathInfo}" ); routes.IgnoreRoute( "Content/{*relpath}" ); routes.RouteExistingFiles
= true ; routes.MapRoute( "photo" , "premium/photos/{accountNo}/{image}" , new {
controller = "Photo" ,
action = "Index" } ); routes.MapRoute( "Default" , "{controller}/{action}/{id}" , new {
controller = "Home" ,
action = "Index" ,
id = UrlParameter.Optional } ); } |
IgnoreRoute 告訴路由模塊 routing module 不要處理這些請求,請注意:需要在RouteExistingFiles=true之前調用ignoreroute方法。.
避免客戶端緩存
最後一個問題就是瀏覽器緩存。瀏覽器會緩存圖片,未授權用戶能夠看到這些緩存的受限圖片,通過 OutputCache attribute告訴瀏覽器不要緩存這些圖片即可
1
2
3
4
5
6
|
[PhotoAuthorize] [OutputCache(NoStore
= true ,
Duration = 0, VaryByParam = "None" )] public FileResult
Index() { return File(Request.RawUrl,
"image/jpeg" ); } |