2016-02-23 63 views
10

在WIF之前,Application_PostAcquireRequestState是創建自定義標識的好地方,但需要很多框架才能確保您所做的每種類型的認證都被恰當地映射。通過自定義標識,我的意思是繼承自身份的類,例如下面的SomeIdentity,以便我們可以擁有一個特定的屬性,我們可能需要所有經過身份驗證的用戶擁有。何處在MVC應用程序中使用WIF創建自定義標識?

PostAcquirerequestState仍然可用,但有很多新的方法可以與身份驗證掛鉤。另外,當支持多種認證方法時,舊方法變得複雜。

我想知道是否有比下面更好的方式來實現WIF現在。主要我想分離處理標識映射聲明的代碼。其思想是,對於其他認證類型​​/提供者,代碼會有所不同,因爲它檢索屬性值的方式可能不是來自諸如SAML之類的聲明,而是來自其他類型認證方法的其他地方。目前,我正在使用Kentor.AuthServices來支持SAML。雖然可能有不同的代碼根據提供者來映射這些值,但最終的結果是SomeIdentity實例已創建,並且SomeProperty和其他屬性將被設置。通過這種方式,應用程序的其餘部分總是可以依賴/假定已經被處理。

我的MVC項目帶有一個AccountController,它有一個ExternalLoginCallback,這個名字暗示可能是完成外部認證(對我來說SAML是一個「外部」認證)的好鉤子。但是,在SAML身份驗證期間/之後的任何時候,它似乎都沒有受到攻擊。

這可能是答案,我們仍然需要將自己的舊方式拼湊在一起,但我希望WIF有一些更好的框架鉤子使這更容易。

public sealed class SomeIdentity : Identity 
{ 
    ... 
    // Some custom properties 
    public string SomeProperty { get;set;} 
} 

protected void Application_PostAcquireRequestState(object sender, EventArgs e) 
{ 
    ... 
    identity = new SomeIdentity(id, userId); 
    // map a claim to a specific property 
    identity.SomeProperty = ...Claims[IdpSomePropertyKey]; 
    ///... 

    GenericPrincipal newPrincipal = new GenericPrincipal(identity , null); 
    HttpContext.Current.User = newPrincipal; 
    System.Threading.Thread.CurrentPrincipal = newPrincipal; 
} 

現在,我使用WIF,在那裏我應該把代碼特定於某個特定的身份驗證類型(即。Kentor.AuthServices SAML),它創建了一個自定義的SomeIdentity?

這個想法是,SomeIdentity將是在我的應用程序中到處使用的身份類,但是填充它的屬性的代碼需要專門爲每個身份驗證類型編寫,比如使用SAML來提取聲明並使用它們的值設置proeprties。即它就是映射發生的地方。

+0

你試圖尋找到簡單的例子? https://github.com/valkovnet/IdentityServer,https://github.com/IdentityServer/IdentityServer2。實際上,主要的技巧是在Web.config中配置Identity Server。這將爲您提供FederatedAuthentication訪問 – deeptowncitizen

+0

簡單的示例通常只是基於web.config的簡單配置,沒有自定義標識。我看了一下valkovnet的例子,它只是當你生成一個新項目然後在web.config中設置WIF時得到的解決方案。除非我沒有找到正確的地方,否則沒有真正的程序化配置或身份設置。 – AaronLS

+0

這是一個OWIN應用程序嗎?你有一個App_Start文件夾嗎? –

回答

4

好吧,我要對此進行一次刺探,希望我能理解你的問題,而不是對你的代碼做太多的假設。我將要做的假設是這是一個全新的MVC應用程序,使用Visual Studio ASP.NET 4.6模板和「無身份驗證」選項創建(根據我瞭解的情況來判斷,您不希望存儲此數據就像剛剛從索賠中讀到的一樣)。

添加一個名爲入門級到項目

using Microsoft.Owin; 
using Owin; 

[assembly: OwinStartup(typeof(WebApplication1.Startup))] 

namespace WebApplication1 
{ 
    public partial class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      ConfigureAuth(app); 
     } 
    } 
} 

現在,這是要運行,因爲你可能已經猜到的根,在「啓動」就像一個文件的global.asax.cs做。

現在我們需要實際製作ConfigureAuth()方法。這通常在App_Start文件夾中使用名爲「Startup.Auth.cs」的文件完成。這個文件將當前不存在,所以,儘管有此模板

using Owin; 
using Kentor.AuthServices.Owin; 

namespace WebApplication1 
{ 
    public partial class Startup 
    { 
     private void ConfigureAuth(IAppBuilder app) 
     { 
     } 
    } 
} 

創建這是我們要做我們的驗證邏輯/設置。 OWIN提供了很多開箱即用的認證策略,還有一些庫甚至更多。如果你打算自己寫,我建議你看看OwinOAuthProviders

繼續並安裝NuGet軟件包Kentor.AuthServices.Owin軟件包和依賴項。這應該可以解決您目前的編譯錯誤。您還需要將對System.IdentityModel的引用添加到您的項目中以備後用。

現在,在Startup.Auth.cs中的ConfigureAuth方法中,您可以通過執行以下操作將Kentor添加到您的應用程序中。

Public void ConfigureAuth(IAppBuilder app) 
{ 
    var kentorOptions = new KentorAuthServicesAuthenticationOptions(true); 
} 

現在你的,因爲我通過它真正的,會從你的WebConfig設置讀取變量kentorOptions。你也可以在這裏手動配置它們。

我們感興趣的部分是kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager屬性。我們想要創建一個自定義的ClaimsAuthenticationManager來提供基於傳入聲明的身份。

請從ClaimsAuthenticationManager

using System.Security.Claims; 

namespace WebApplication5 { 
    public class CustomClaimsAuthManager : ClaimsAuthenticationManager { 
     public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal) { 
      ClaimsIdentity ident = (ClaimsIdentity) incomingPrincipal.Identity; 
      //Use incomingPrincipal.Identity.AuthenticationType to determine how they got auth'd 
      //Use incomingPrincipal.Identity.IsAuthenticated to make sure they are authenticated. 
      //Use ident.AddClaim to add a new claim to the user 
      ... 
      identity = new SomeIdentity(id, userId); 
      // map a claim to a specific property 
      identity.SomeProperty = ...Claims[IdpSomePropertyKey]; 
      ///... 

      GenericPrincipal newPrincipal = new GenericPrincipal(identity, null); 
      return newPrincipal; 
     } 
    } 
} 

繼承這就是你有你的身份代碼的類。現在最後我們需要將其設置爲ClaimsAuthenticationManager來實際使用,並告訴您的應用程序在OWIN管道中使用Kentor。這一切都在Startup.Auth.cs文件中。

private void ConfigureAuth(IAppBuilder app) { 
      var kentorOptions = new KentorAuthServicesAuthenticationOptions(true); 
      kentorOptions.SPOptions.SystemIdentityModelIdentityConfiguration.ClaimsAuthenticationManager = new WebApplication5.CustomClaimsAuthManager(); 
      app.UseKentorAuthServicesAuthentication(kentorOptions); 
     } 

Annnndd應該有希望做到這一點!對於其他驗證提供者,像OwinOAuthProviders的那些,也可以通過重寫options.Provider方法上做不同的事件的東西,像這樣的事情處理:

var cookieOptions = new CookieAuthenticationOptions { 
       AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
       LoginPath = new PathString("/Auth/Login"), 
       CookieName = "cooooookiees", 
       ExpireTimeSpan = new TimeSpan(10000, 0, 0, 0, 0), 
       Provider = new CookieAuthenticationProvider { 
        OnException = context => { 
         var x = context; 
        }, 
        OnValidateIdentity = async context => { 
         var invalidateBySecurityStamp = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
         validateInterval: TimeSpan.FromMinutes(15), 
         regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)); 
         await invalidateBySecurityStamp.Invoke(context); 

         if (context.Identity == null || !context.Identity.IsAuthenticated) { 
          return; 
         } 
         var newResponseGrant = context.OwinContext.Authentication.AuthenticationResponseGrant; 
         if (newResponseGrant != null) { 
          newResponseGrant.Properties.IsPersistent = true; 
         } 

        } 
       } 
      }; 
      app.UseCookieAuthentication(cookieOptions); 
+0

看起來正是我所需要的。主要的事情是我曾看過索賠**授權**經理教程,確定這是錯誤的事情,從來沒有看過索賠**身份驗證**經理。一旦我確認,我會重新提交賞金和獎勵。 – AaronLS

+0

@AaronLS是的,這也讓我絆倒了不止一次。身份驗證就是您要分配聲明等的地方,授權是您想要根據這些聲明拒絕或授予訪問權限的位置。很高興我能幫上忙!我知道我在這之前曾經受過一次這樣的痛苦,所以希望這可以節省一些人從我的學習上的痛苦。 –

+0

在IsAuthenticated成功設置的情況下獲得此項工作。但是,我返回一個帶有實現IIdentity的CustomIdentity的GenericPrincipal,但**不**繼承自ClaimsIdentity。在Global asax中,PostAcquireRequestState仍顯示ClaimsIdentity和ClaimsPrincipal。我也明確地將它設置在'HttpContext.Current.User'和'System.Threading.Thread.CurrentPrincipal'上,但似乎總是在其他地方使用空聲明來設置ClaimsPrincipal,但它繼承了IsAuthenticated true。也許non-ClaimsIdentity不被很好的支持? – AaronLS

相關問題