ASP.NET Web API的安全管道

来源:http://www.cnblogs.com/darrenji/archive/2016/03/17/5290073.html
-Advertisement-
Play Games

本篇體驗ASP.NET Web API的安全管道。這裡的安全管道是指在請求和響應過程中所經歷的各個組件或進程,比如有IIS,HttpModule,OWIN,WebAPI,等等。在這個管道中大致分兩個階段,一個是驗證階段,另一個是授權階段。在ASP.NET Web API v1版本的時候,安全管道大致


 

本篇體驗ASP.NET Web API的安全管道。這裡的安全管道是指在請求和響應過程中所經歷的各個組件或進程,比如有IIS,HttpModule,OWIN,WebAPI,等等。在這個管道中大致分兩個階段,一個是驗證階段,另一個是授權階段。

在ASP.NET Web API v1版本的時候,安全管道大致是這樣的:

→ Authentication,請求來到IIS中的HttpModule
→ Authenticatin, 請求來到API的HttpMessageHandler
→ Authorization, 請求來到Authorization Filter
→ Authorization, 請求來到Controller

當ASP.NET Web API來到v2版本的時候,安全管道大致是:

→ 請求來到Host中的OWIN組件
→ 請求來到MessageHandler,全局或按每個請求
→ 請求來到Authentication Filter
→ 請求來到Authorization Filter

可見,加入了OWIN組件,OWIN是開源的, Microsoft在此基礎上開發出了Katana驗證中間件。

我們知道,ASP.NET Web API的宿主有兩種方式:

1、Web宿主,ASP.NET, IIS
2、自宿主,WCF,.NET進程

如果把OWIN考慮進去,那就是:
1、IIS→ASP.NET+OWIN Bridge→ OWIN→Web API + OWIN Adapter
2、Process/Host+OWIN Bridge→OWIN→Web API + OWIN Adapter

一、瞭解管道中的各個組件


1.1 OWIN中間件

 

public class AuthenticationMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> _next;
    
    public AuthenticationMiddleware(Func<IDictionary<string, object>, Task> next)
    {
        _next = next;
    }
    
    public async Task Invoke(IDictionary<string, object> env)
    {
        //檢查env集合,進行驗證
        env["server.user"] = CreatePrincipal();//設置principal;
        await _next(env);
    }
}

 

OWIN中間件的大致工作原理是:請求中的Header,Body,路由等信息被放在了IDictionary<string, object>這個字典集合中,並且提供了Invoke方法,把獲取到的用戶信息放在env["server.user"]中,並且調用一個動作處理IDictionary<string, object>集合。


1.2 Katana Authentication Middleware

這是Microsoft基於OWIN開發出來的驗證組件,大致是:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticaitonOptions{
            AuthenticationType = "Cookies",
            //more
        });
        
        app.UseGoogleAuthentication(new GoogleAuthenticationOptions{
            AuthenticationType = "Google";
            //more
        });
        
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions{
            AuthenticationType = "Bearer";
            // more
        })
    }
}

以上,至少可以看出,可以為OWIN組件選擇驗證方式。

1.3 Message Handler

實施在全局或某個請求上。大致是:

public class MyHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        //檢查請求
        
        var response = await base.SendAsync(request, cancellationToken);
        
        //檢查響應
        return response;
    }
}

 

Message Handler從ASP.NET WEB API 2以後就不存在了。

 

1.4 Authentication Filter 驗證過濾器

可以在全局配置:

WebApiConfig.cs
config.Filters.Add(new HostAuthenticationFilter("Bearer"));

當然過濾器也可以放在控制器和方法層面:

[HostAuthentication("Bearer")]
public class TestController : ApiController
{
    [HostAuthentication("Google")]
    public HttpResponseMessage Get(){}
    
    [OverrideAuthentication]
    [HostAuthentication("Cookies")]
    public HttpResponseMessage Delete(){}
}

 

1.5 Authorization Filter 授權過濾器

 

[Authorize]
public class DataController : ApiController
{
    [AllowAnonymous]
    public Data Get(){}
    
    [Authorize(Role = "Foo")]
    public HttpResponseMessage Delete(int id){}
}

如果授權失敗,返回401報錯。

1.6 獲取用戶的Identity

通過ApiController的User屬性獲取到用戶的Identity。註意,User屬性值可能為null。

二、通過例子來體驗安全管道


2.1 自定義HttpModule

首先,請求過來,肯定要通過HttpModule。我們需要自定義一個HttpModule,通過一個版主方法把當前的用戶信息列印出來。

 

namespace SecurityPipeline
{
    public class HttpModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += context_BeginRequest;
        }
        
        void context_BeginRequest(object sender, EventArgs e)
        {
            Helper.Write("HttpModule", HttpContext.Current)
        }
        
        public void Dispose()
        {
        
        }
    }
}

namespace SecurityPiepeline
{
    public static class Helper
    {
        public static void Write(string state, IPrincipal principal)
        {
            Debug.WriteLine("------------" + stage + "--------");
            if(principal == null || principal.Identity == null  || !principal.Identity.IsAuthenticated)
            {
                Debug.WriteLine("anonymous user");
            }
            else
            {
                Debug.WriteLine("User:" + principal.Identity.User);
            }
            
            Debug.WriteLine("\n");
        }
    }
}

 

可見,HttpContext.Current是IPrincipal類型。

然後這是一個Web項目,需要把HTTP module註冊一下。

 

<configuration>
    <system.webServer>
        <modules>
            <add name="DemoModule" type="SecurityPipeline.HttpModule"/>
        </modules>
    </system.webServer>
</configuration>

 

如果此時項目下有一個default.html頁面的話,運行項目,展示default.html的時候,控制台列印出如下信息:

-----HttpModule-------
anonymouse

顯然,請求過來,自定義的Http Module起了作用,但目前還不能從IPrincipal中拿到User信息。

2.2 安裝ASP.NET Web API 2

2.3 創建控制器

 

using System.Net.Http;
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //獲取用戶也可以這樣寫
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 

以上,通過ApiController的User屬性獲取到IPincipal類型。

2.4 安裝Microsoft.Owin.Host.SystemWeb

2.5 安裝Microsoft. ASP.NET Web API 2.1 OWIN

2.6 創建Startup類

 

using OWin;
using System.Web.Http;

namespace SecurityPopeline
{
    public class Startup
    {
        public void Configuraiton()
        {
            var configuration = new HttpConfiguration();
            configuration.Routes.MapHttpRoute("default", "api/{controller}");
            
        }
    }
}

這裡,讓WEB API的HttpConfiguraton實例賦值給類OWIN的IAppBuilder的UseWebApi方法。

2.7 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Controller--------
anonymous user

可見,請求一路經過管道中的HttpModule和Controller,但依然沒有拿到用戶信息。

2.8 創建TestMiddleware類

進入HttpModule之後,和進入Controller之前,這裡是OWIN組件的生存之地。

 

using Microsoft.Owin;

namespace SecurityPopeline.Pipeline
{
    public class TestMiddleware
    {
        private Func<IDictionary<string, object>, Task> _next;
        public TestMiddleware(Func<IDictionary<string, object>, Task> next)
        {
            _next = next;
        }
        
        public async Task Invoke(IDictionary<string, object> env)
        {
            var context = new OwinContext(env);
            Helper.Write("Middleware", context.Request.User);
            await _next(env);
        }
    }
}

 

2.9 Startup類中增加有關TestMiddleware部分

 

using OWin;
using System.Web.Http;

namespace SecurityPopeline
{
    public class Startup
    {
        public void Configuraiton(IAppBuilder app)
        {
            var configuration = new HttpConfiguration();
            configuration.Routes.MapHttpRoute("default", "api/{controller}");
            
            app.Use(typeo(TestMiddleware));
            
            app.UseWebApi(configuration);
        }
    }
}

 

3.10 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Middleware--------
anonymous user

------Controller------
anonymous user

可見,請求一路過來歷經管道中的HttoModule, OWIN, 最後到達Controller,依然沒有獲取到用戶信息。

3.11 添加TestAuthenticationFilterAttribute類

在OWIN和Controller之間,還有驗證的介面,這也是安全管道中的一個重要環節。

 

using System.Web.Http.Filters;
using System.Threading.Tasks;

namespace SecurityPipeline.Pipeline
{
    public class TestAuthenticationFilterAttribute : Attribute, IAuthenticationFilter
    {
        public async Task AuthenticateAsync(HttpAuthenticationContext context)
        {
            Helper.Write("AuthenticationFilter", context.ActionContext.RequestContext.Principal, CancellationToken..)
        }
        
        public async Task ChallengeAsync(HttpAuthenticationContext context, CancellationToken..)
        {
        
        }
        
        public bool AllowMultiple
        {
            get {
                return false;
            }
        }
    }
}

 

控制器增加過濾特性

 

using System.Net.Http;


[TestAuthenticationFilter]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //獲取用戶也可以這樣寫
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 

3.12 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Middleware--------
anonymous user

------AuthenticationFilter--------
anonymous user

------Controller------
anonymous user

可見,請求路徑安全管道中的HttpModule,OWIN,驗證,依然沒有獲取到用戶信息。

3.13 增加TestAuthorizationFilterAttrbute類

在經過驗證特性,以及進入Controller或Action之前,安全管道中還有一個重要的成員,就是授權特性。

 

public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal);
        
        return base.IsAuthorized(actionContext);
    }
}

 

控制器增加授權特性

 

using System.Net.Http;


[TestAuthenticationFilter]
[TestAuthorizationFilter]
public class TestController : ApiController
{
    public IHttpActionResult Get()
    {
        Helper.Write("Controller", User);
        
        //獲取用戶也可以這樣寫
        //Helper.Write("Controller",Request.GetRequestContext().Principal);
        return Ok();
    }
}

 

3.14 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Middleware--------
anonymous user

------AuthenticationFilter--------
anonymous user

------AuthorizationFilter--------
anonymous user

並報錯:Authorization has been denied for this request

可見,在請求還沒有到達Controller之前,就開始報錯了。

於是,修改TestAuthorizationFilterAttrbute類如下:

public class TestAuthorizationFilterAttribute : AuthorizeAttibute
{
    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        Helper.Write("AuthorizationFilter", actionContext.RequestContext.Prioncipal);
        
        //return base.IsAuthorized(actionContext);
        return true;
    }
}

 

3.15 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Middleware--------
anonymous user

------AuthenticationFilter--------
anonymous user

------AuthorizationFilter--------
anonymous user

------Controller--------
anonymous user

可見,路由一路經過安全管道中的HttpModule, OWIN, AuthenticaitonFilter, AuthorizationFilter, Controller,依然沒有獲取到用戶信息?

3.16 用戶信息從哪裡註入呢?

接下來要修改TestMiddleware類

 

using Microsoft.Owin;
using System.Security.Principal;

namespace SecurityPopeline.Pipeline
{
    public class TestMiddleware
    {
        private Func<IDictionary<string, object>, Task> _next;
        public TestMiddleware(Func<IDictionary<string, object>, Task> next)
        {
            _next = next;
        }
        
        public async Task Invoke(IDictionary<string, object> env)
        {
            var context = new OwinContext(env);
            
            //authentication
            //new string[]數組存放用戶
            context.Request.User = new GenericPrincipal(new GenericIdentity("dom"),new string[]{});
            
            Helper.Write("Middleware", context.Request.User);
            await _next(env);
        }
    }
}

 

3.17 請求路由:localhsot:8000/api/test

顯示
------HttpModule--------
anonymous user

------Middleware--------
User: dom

------AuthenticationFilter--------
User: dom

------AuthorizationFilter--------
User: dom

------Controller--------
User: dom


總結:請求一路過來,會經過安全管道中的HttpModule, OWIN,AuthenticaitonFilter, AuthorizationFilter, Controller,最後到達Action, 而用戶信息可以在OWIN中註入。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 開始學習hadoop啦!!! 在Ubuntu14.04上新建了一個名為hadoop的用戶,但總是遇到各種許可權問題,於是就想乾脆把這個賬戶變成root賬戶。 網上查到說是直接修改/etc/sudoers,修改時提示read-only,修改不了,自然而然想到去修改文件的許可權, sudo chown u+
  • 三、gdb調試(下)01.查看運行時數據print - 查看變數值ptype - 查看類型print array - 查看數組print *array@len - 查看動態記憶體print x =5 - 改變運行時數據#vi simple.c#include<stdio.h>long fun(int
  • 系統來自系統媽:http://www.xitongma.com 電腦公司最新GHOST win7系統32位優化精簡版V2016年3月 系統概述 電腦公司ghost win7 x86(32位)萬能裝機版集成的軟體符合電腦公司及電腦城裝機絕大多數人要求及喜好,既大眾,又時尚,人人喜歡,處處適用。自動判斷
  • asp.net 編譯錯誤類型“同時存在於”不同的dll中. 出現這種錯誤大概有三種情況: 1、ASPX頁面,一個*.ASPX,對應著一個*.cs文件,兩者其實是一個文件,通過兩者實現代碼分離,每個*.aspx頁面都引用著自身的CS文件:如果兩個頁面引用了相同得.CS文件,在發佈得時候也會出現這種錯誤
  • 普通電腦沒有通用的輸入輸出口(GPIO),但有時候我就想輸入一個開關量。 比如讓用戶拉一下拉繩開關就啟動某個應用,比如裝一個觸點開關判斷門是打開的還是關閉的,比如.... 需求是如此簡單,你都不願意花幾十塊錢去買一個單片機,更不用說PCI擴展卡、PLC之類的了。。怎麼辦吶? 有辦法!最簡單的用串口就
  • 運行-cmd,輸入下麵命令:C:\WINDOWS\Microsoft.NET\Framework\v版本號\aspnet_regiis.exe -i即可 以下是aspnet_regiis.exe參數的說明信息: -i - 安裝 ASP.NET 的此版本,並更新 IIS 元資料庫根處的腳本映射和根以下
  • 使用ASP.NET模版生成HTML靜態頁面並不是難事,主要是使各個靜態頁面間的關聯和鏈接如何保持完整。本文介紹了使用ASP.NET模版生成HTML靜態頁面的五種方案。 ASP.NET模版生成HTML靜態頁面方案1: 你可以用這個函數獲取網頁的客戶端的html代碼,然後保存到.html文件里就可以了。
  • 泛型是CLR和編程語言提供的一種特殊機制,它用於滿足“演算法重用” 。 可以想象一下一個只有操作的參數的數據類型不同的策略模式,完全可以用泛型來化為一個函數。 以下是它的優勢: 這就是為什麼List<T>淘汰了ArrayList的原因,特別是在進行值類型操作時,因為裝箱拆箱過多而差距很大。 約定:泛型
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...