身份驗證/授權 MVC 5 和 Web API - Katana/Owin
我在嘗試決定承擔我的項目的路線時遇到問題。
我一直在閱讀 OWIN 規範和 .NET 中的 Katana 實現。我想使用 Katana 路線的原因是因為與 ADFS 和 Token/Cookie 生成相關的 owin 組件。
我有兩個項目,一個用於 MVC 5 網站,一個用於 Web API。將來它們可能位於兩台不同的伺服器上,但現在它們在同一台伺服器上。
我知道我將使用 IIS,因此我不需要調查 Owin 管道。
我的要求是,有些使用者將使用 ADFS 登錄,而其他使用者將使用 Token/Cookie 生成以及角色/成員資格提供程序登錄。根據誰通過身份驗證,我的網頁的某些部分將被公開。網頁工程師是在剃刀中完成的。
有沒有人可以閱讀任何材料來幫助解釋我可以採用的設計流程?或者有人做過類似於我正在經歷的項目,可以添加任何建議?有很多不同的文件描述了我需要的具體事物,但不是全域;就像只談論 WebAPI 和 ADFS,或者 WebAPI 和 windows azure 等。
我的理論是在MVC5網站項目上實現認證/授權,在Web API上進行授權(不知何故兩者之間需要存在通信)。然後我可能會為 ADFS 創建一個項目副本並為令牌/cookie 身份驗證創建另一個副本?或者也許我必須進行 4 種不同類型的身份驗證:2 種用於我對 MVC5 網站和 Web API 進行身份驗證的 adfs,另外 2 種用於令牌/cookie 生成。
任何建議都會有所幫助,因為我對這種技術不是很熟悉。
我可以提供 OWIN 中的 WsFederation 選項很好,但需要 cookie……而且它們是與帶有 cookie 的本地身份驗證不同類型的 cookie。ADFS 2.0/WsFederation 使用 AuthenticationType=“Cookies”,本地身份驗證使用 AuthenticationType=“ApplicationCookie”。據我所知,它們顯然是不相容的。我認為您必須對 ADFS 使用令牌身份驗證,但我認為這需要 2012R2 上的 ADFS 3.0。為此,請使用 OWIN OAuth。
更新:在研究了一段時間後,我想出瞭如何讓這兩種身份驗證類型在同一個 Web 應用程序中和平共存。使用 OWIN,設置兩次呼叫 UseCookieAuthentication,一次啟用新的 WsFederationAuthentication 中間件,再次啟用本地 cookie 身份驗證。這並不直覺,但在幕後,為每個指定不同的身份驗證類型將它們設置為不同的身份驗證“引擎”。這是它在我的 Startup 中的外觀:
app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new PathString("/Account/Login"), Provider = new CookieAuthenticationProvider { OnResponseSignIn = ctx => { ctx.Identity = TransformClaims(ctx, app); } } }); app.UseCookieAuthentication(new CookieAuthenticationOptions { Provider = new CookieAuthenticationProvider { OnResponseSignIn = ctx => { ctx.Identity = TransformClaims(ctx, app); } } }); app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions { Wtrealm = Realm, MetadataAddress = Metadata, Caption = "Active Directory", SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType });這成功地允許使用者對本地 SQL 表或 ADFS 2.0 進行身份驗證。TransformClaims 標註允許我規範這兩個提供者之間的聲明,以便它們保持一致。
編輯:這是一個非常基本的 TransformClaims。你可以在其中做很多事情:從你的數據庫中獲取使用者,設置導航聲明,自定義權限,角色集合等等。我剛剛從一個更大的實現中建構了這個精簡版本,所以我沒有執行它,但希望您了解如何利用 OnResponseSignIn 事件。
private static ClaimsIdentity TransformClaims(CookieResponseSignInContext ctx, IAppBuilder app) { var ident = ctx.Identity; var claimEmail = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Email); var claimName = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Name); //normalize my string identifier var loginString = (claimEmail != null) ? claimEmail.Value : (claimName != null) ? claimName.Value : null; var efctx = ctx.OwinContext.Get<DBEntities>(); var user = UserBL.GetActiveUserByEmailOrName(efctx, loginString); if (user == null) { //user was auth'd by ADFS but hasn't been auth'd by this app ident.AddClaim(new Claim(ClaimTypesCustom.Unauthorized, "true")); return ident; } if (ident.Claims.First().Issuer == "LOCAL AUTHORITY") { //Local //local already has claim type "Name" //local didn't have claim type "Email" - adding it ident.AddClaim(new Claim(ClaimTypes.Email, user.Email)); } else { //ADFS //ADFS already has claim type "Email" //ADFS didn't have claim type "Name" - adding it ident.SetClaim(ClaimTypes.Name, user.UserName); } //now ident has "Name" and "Email", regardless of where it came from return ident; }