簡體   English   中英

ASP.NET MVC+API 和 WCF,具有針對自定義數據庫和活動目錄的基於聲明的授權和身份驗證

[英]ASP.NET MVC+API and WCF with claims-based authorization and authentication against a custom DB and active directory

我們正在開發兩個(新的)ASP.NET 應用程序,它們使用 MVC/Razor 視圖作為模板引擎來處理 I18N/L10N(當前文化存儲在每個請求的 cookie 中並從中檢索;文本從資源)。

這兩個應用程序通過托管在與 MVC 應用程序相同的 ASP.NET 應用程序中的單獨 WebApis 使用相同的 WCF 服務。 API 和由基於 Web 的應用程序 (HTML/JS) 訪問。

應用程序A當前使用表單身份驗證(WCF 服務根據我們的應用程序數據庫驗證用戶憑據),應用程序B使用 Windows 身份驗證。

TL;DR 摘要:我們需要了解 WCF 服務中有關 Web 用戶的信息。

我們需要:

  • 有權訪問 WCF 服務中的當前(Web)用戶身份
  • 傳輸有關該身份的可驗證信息(例如角色、組成員資格等)並使用該信息來限制查詢和操作(即僅允許查看和編輯您自己組中的數據)。
  • 在應用程序B 中透明地驗證用戶(我們不希望在 IE 中出現單獨的登錄屏幕或彈出窗口)
  • 支持通過一次性密碼登錄,其中身份驗證發生在帶外(例如,用戶獲得一個僅短暫有效的訪問代碼,它對他/她自己進行身份驗證,就好像他使用他的憑據登錄一樣)
  • 有短暫的會話/令牌生命周期,但使用滑動過期 - 用戶活動應該延長他的會話/令牌生命周期。 非活動用戶應在短時間不活動后注銷。
  • 在與 WCF 服務通信時具有消息安全性(理想情況下,由於需要模擬/委托,沒有基於證書的實際身份驗證的證書?)

到目前為止,我對此的想法和印象是:

  • 基於聲明的授權可以很好地將授權與業務邏輯分離
  • 基於聲明的身份驗證/授權似乎可以傳輸我們需要限制可用數據和操作的所有信息(即從聲明中讀取組成員身份)
  • 基於令牌的身份驗證是基於聲明的身份驗證(令牌是傳輸聲明的方式)
  • 我需要一個安全令牌服務來驗證用戶 (IdentityServer)
  • 在 WCF 通道創建期間可以以某種方式使用令牌來傳輸當前(聲明)主體或相應的令牌。
  • 從表單遷移到基於令牌的身份驗證時,我必須為我們的 Web 客戶端使用資源所有者密碼憑據流

到目前為止,我有:

  • 使用 ROPC 流為單個客戶端設置 IdentityServer
  • 將 OWIN 添加到 Web 應用程序 A 並使用app.UseCookieAuthenticationapp.UseIdentityServerBearerTokenAuthentication來設置身份驗證,但我不太確定這到底意味着什么,所以我現在不太滿意。
  • 在登錄時(通過 MVC),我通過TokenClient.RequestResourceOwnerPasswordAsync(username, password, scopes)從 IdentityServer 請求一個(訪問?)令牌,嘗試通過訪問用戶信息來構建ClaimsIdentity 端點並通過Request.GetOwinContext().Authentication.SignIn(id);設置 cookie Request.GetOwinContext().Authentication.SignIn(id); .
  • 對基於令牌的身份驗證和基於聲明的授權如何工作的基本了解

我沒有的:

  • 有信心我完全理解基於聲明的授權是如何工作的,並且可以在 WCF、MVC 和 WebApi 中實現
  • 不知道不同的 OWIN 中間件和擴展( UseIdentityServerBearerTokenAuthenticationUseOpenIdConnectAuthentication等)實際上做了什么,應該如何以及何時使用它們以及具有什么安全隱患。
  • 知道wS2007FederationHttpBinding作用和用途,或者我必須在Startup.cs配置的內容以及需要在web.config或其他地方配置的內容
  • 如何使用適當的證書、SSL/HTTPS 保護所有內容,以便我可以在我們團隊的開發和部署期間使用它(我們為每個開發人員以及每個構建配置進行了配置轉換)

基本上,我已經閱讀了太多關於 WCF、WIF 等的信息,以至於我不清楚當前的信息是什么、最佳實踐是什么以及我如何實施符合我們所有要求的東西。 IdentityServer 中的示例並沒有真正幫助我,因為對我來說,它們沒有解釋任何內容。

對此的任何幫助將不勝感激,即使您只是幫助我更好地理解術語和技術。

PS:我們正在運行 .NET 4.6

更新:我設法從 IdentityServer 檢索令牌並查詢 userinfo 端點以獲取聲明。 結果我使用了ClaimTypes.Email等而不是Constants.ClaimTypes.Email - 同樣只有身份范圍會在 userinfo 端點上產生聲明,我在我的資源范圍內指定了它們。

我的下一步是試圖弄清楚UseIdentityServerBearerTokenAuthentication如何阻止我訪問任何東西,以及如果我刪除任何必需的范圍,為什么它不會......

更新: (2015-12-01) 我目前正在嘗試以某種方式透明地將令牌傳輸到 WCF 服務,並根據令牌提供當前委托人(或聲明委托人)。 我還沒有明確的方法來實現這一目標。

MVC 和 WebApi 的東西現在似乎工作正常:

MVC 應用程序使用 OWIN cookie 中間件進行保護 - 在使用表單身份驗證的登錄時,我使用TokenClient和資源所有者密碼憑據流。 然后我查詢userinfo (通過UserInfoClient )和introspection (通過IntrospectionClient )端點來構建聲明,創建一個ClaimsIdentity並將其保存在 cookie 中。 我還將訪問令牌保存為聲明。

var id = new ClaimsIdentity(listOfClaims, "Cookies");
this.Request.GetOwinContext().Authentication.SignIn(id);

陷阱:內省端點需要作為范圍而不是客戶端進行身份驗證 - 這在示例中有點誤導,其中客戶端和范圍具有相同的名稱

為了驗證每個請求上的令牌,我將CookieAuthenticationOptionsProvider配置為一個new CookieAuthenticationProvider() ,我在OnValidateIdentity期間查詢 IdentityServer 的內省端點:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = "Cookies",
    LoginPath = new PathString("/User/Login"),
    LogoutPath = new PathString("/User/Logoff"),
    // setup more options etc..

    Provider = new CookieAuthenticationProvider()
    {
        OnValidateIdentity = async context =>
        {
            // validate etc. - and if it fails call: context.RejectIdentity();
        }
    }
}

通過擴展用於設置Register(HttpConfiguration config)Register(HttpConfiguration config)Register(HttpConfiguration config)與 cookie 身份驗證分離:

// prevent use of owin cookie auth
config.SuppressDefaultHostAuthentication();

// need bearer token auth
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

此外,我已經在 owin 啟動中設置了IdentityServerBearerTokenAuthentication (基本上,這是我對 WebApi 所做的唯一事情,因為我有幾個通往多個 API 的路由,並且無法通過 Ninject 設置具有依賴項注入的多個地圖......)。

 app.Map(
    "/api",
    inner =>
    {
            inner.UseIdentityServerBearerTokenAuthentication(identityServerBearerTokenAuthenticationOptions);
    });

當然,僅憑這一點就意味着 angular 應用程序將無法獲取任何數據 - 因此在單頁應用程序視圖中,我將令牌作為常量注入到配置中,並通過配置$httpProvider設置默認標頭:

看法:

<script type="text/javascript">
  angular.module("myApp").constant("authorizationHeader", "Bearer @Model");
</script>

應用程序:

myApp.config(["$httpProvider", "authorizationHeader", function ($httpProvider, authorizationHeader) {
    $httpProvider.defaults.headers.common["Authorization"] = authorizationHeader;
}]);

...所以我現在唯一的問題幾乎是如何將令牌傳輸到 WCF 服務以及如何從該服務上的令牌設置聲明標識(無需明確地這樣做 - 即我不想要一個單獨的我的合同上的參數)

PS:我只能在app.config配置 WCF 服務,因為我們使用的是自托管 WCF 服務和 Ninject ...

2015-12-10更新成功!

我將參考令牌傳輸到 WCF 服務,類似於 Dominick Baier 建議的做法: http : //leastprivilege.com/2015/07/02/give-your-wcf-security-architecture-a-makeover-with-identityserver3/

本質上這歸結為:

  • 包裹在令牌的參考Claim在新ClaimsIdentity
  • 為該身份創建一個新的SecurityTokenDescriptor
  • Saml2SecurityTokenHandler包裝
  • 包裝在GenericXmlSecurityToken
  • 通過this.ChannelFactory.CreateChannelWithIssuedToken(xmlToken);創建頻道this.ChannelFactory.CreateChannelWithIssuedToken(xmlToken); (提示:緩存ChannelFactory而不是Channel

這意味着我必須將綁定更改為ws2007FederationHttpBinding ,將所有 url 更改為使用https4430044399范圍內的端口在本地主機上進行開發(因為 Windows 已經為這些端口預配置了證書和訪問控制列表 - 對於部署,您必須添加您的證書並允許 WCF 主機用戶在那里托管 HTTP/SSL 服務)。 如果任何元數據端點可見,那么它們也必須使用 HTTPS( binding="mexHttpsBinding"<serviceMetadata httpGetEnabled="false" />

為了使用該綁定,安全性必須是TransportWithMessageCredentials

在 WCF 端,我刪除了所有SecurityTokenHandler並添加了我自己的,它解開引用令牌並使用來自 IdentityServer 的introspection端點來構建身份(與來自 IdentityServer 的示例非常相似)。

這可以在代碼或 app.config 中完成( ServiceCommunication是我保存所有這些東西的程序集):

<configSections>
  <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
<system.identityModel>
<identityConfiguration name="identity">
  <securityTokenHandlers>
    <clear />
    <add type="ServiceCommunication.Authentication.IdentityServerWrappedReferenceTokenHandler, ServiceCommunication" />
  </securityTokenHandlers>
  <claimsAuthorizationManager type="ServiceCommunication.Authorization.ClaimsAuthorizationManager, ServiceCommunication"/>
</identityConfiguration>

對於授權,我定義了自己的ClaimsAuthorizationManager ,它處理覆蓋的CheckAccess方法中的所有內容。 注意:每個 WCF 合約方法也會調用該方法。

授權可以在經由任何明碼ClaimsPrincipalPermissionAttribute或通過顯式ClaimsPrincipalPermission 甚至不必是 WCF。 在 .NET 4.5 中開箱即用

我在 WCF 服務和 MVC/API 控制器操作中盡可能深入地使用ClaimsPrincipalPermissionAttribute

現在我已經對所有用戶進行了身份驗證,防止訪問未經身份驗證的用戶(重定向到登錄)並保證只有授權用戶才能訪問特定方法。 :)

所以我終於解決了這一切:

  • 我使用 IdentityServer3 進行所有聲明的身份驗證和管理
  • app.UseCookieAuthentication和我自己的CookieAuthenticationProvider來驗證 MVC 中的引用令牌並像以前的表單身份驗證一樣處理登錄
  • API 的app.UseIdentityServerBearerTokenAuthentication (每個 http 請求必須設置一個標頭Authorize和值Bearer your-token-here ,大多數 JS 框架允許你全局設置)。 身份驗證針對 IdentityServer,我已經配置了 ClientId 和 ClientSecret(實際上是 ScopeId 和 ScopeSecret),以便它使用自省端點。 當心:您只會獲得該特定范圍的聲明,而不會獲得其他范圍的聲明。
  • 各種IdentityModel客戶端進行身份驗證和驗證(並從用戶信息和自省端點獲取聲明)
  • 通過Ws2007FederationHttpBindingTransportWithMessageCredentials安全性包裝的引用或 jwt 令牌
  • 我自己在 WCF 服務上的SecurityTokenHandler解開該令牌並驗證它(並設置身份/主體)
  • 我自己的ClaimsAuthorizationManager通過ClaimsPrincipalPermission ( Attribute ) 進行授權

OAuth2 和 OpenID Connect 等新的 Internet 安全協議不能很好地與 WCF SOAP 服務配合使用。

使用 OAuth2 和 OpenID Connect 協議時,授權服務器會發出 JWT 令牌。 但是,當您使用WS2007FederationHttpBinding時,您的 SOAP WCF 服務需要信封標頭中的 SAML 令牌。 IndentityServer 不發布 SAML 令牌

雖然可以使用來自 JWT 令牌的聲明來發布和簽署您自己的 SAML 令牌,但將 WCF SOAP 服務替換為基於 REST 的服務可能更容易,該服務在Authorization標頭中需要 JWT 令牌。

我不確定您為什么要使用資源所有者密碼憑據流。 您可能需要考慮將 IdentityServer 與現有數據庫一起使用,並改用身份驗證代碼流。

PS IdentityServerKatana (Microsoft 的 OWIN 實現)都是開源的,因此您可以弄清楚所有這些代碼實際上在做什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM