2015-08-27 110 views
1

我正在使用angular和webapi的跨平臺web應用程序。問題是角度應用程序在科爾多瓦容器中運行時。爲了與設備上的其他應用程序一起玩,我需要爲SSO使用插件。此插件是導致我遇到的問題的原因,因爲它執行了一些操作。它攔截所有的http請求,並向由第三方令牌提供者生成的頭添加不記名令牌,所以我不能解碼它,並覆蓋我在頭中設置的任何不記名令牌。它似乎也阻止cookies ..沒有cookie或本地憑證的外部Owin身份驗證

因此,當您無法向您發送自己的本地證書時,它會有點棘手。

於是我開始與https://coding.abel.nu/2014/06/writing-an-owin-authentication-middleware/http://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.OAuth/OAuthBearerAuthenticationHandler.cs

所以我想我應該寫我自己的中間件來照顧這;我認爲既然標準的oauth中間件可以無cookie地工作,我不應該花太多時間讓我的略有不同的不記名的令牌中間件去做。但事實並非如此......編寫我自己的中間件..所以我「M抽到了頭,與外部令牌提供驗證,但我實際上不能登錄。

protected override async Task<AuthenticationTicket> AuthenticateCoreAsync() 
     { 
      try 
      { 
       // Find token in default location 
       string requestToken = null; 
       string authorization = Request.Headers.Get("Authorization"); 
       if (!string.IsNullOrEmpty(authorization)) 
       { 
        if (authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) 
        { 
         requestToken = authorization.Substring("Bearer ".Length).Trim(); 
        } 
       } 
.... Take the Request token call other Server, verify token... 

而且

public override async Task<bool> InvokeAsync() 
    { 
     var ticket = await this.AuthenticateAsync(); 
     if(ticket != null) 
     { 
      this.Context.Authentication.SignIn(new AuthenticationProperties(), grantIdentity); 
      return false; 
     } 
    } 

那麼到底簽到不會導致錯誤或任何東西,但實際上並沒有簽署。只要我使用[Authorize]屬性進行控制器操作,就會得到401。我沒有啓用任何外部cookie。很有可能我錯了,或者我太努力了。

+0

我發現只是重寫授權屬性更簡單。我問了一個類似的問題,這個人給了我以下鏈接(BitOfTech.net)。請發佈,如果你得到這個想通了(http://stackoverflow.com/questions/32099027/webapi-token-issuance-authorization) –

+0

@ Mr.B - 嘿檢查我的答案..我終於能夠做到這一點。 –

回答

0

所以...我更早地回答了它,但是我能夠弄明白,沒有重寫授權屬性。我最終看到了OWIN安全代碼的來源。訣竅是,你真的需要2個OWIN中間件組件。其中一個就是我稱之爲的服務器中間件(我從owin源中偷走了這個)。服務器中間件響應挑戰和/或如果你感覺瘋狂爲你生成本地證書。這個中間件也是一個被動中間件組件。除非有人提出要求,否則我不會獲得本地證書,因爲這有點不合時宜,但如果有人認爲這會有所幫助,我可以更新。

public class LowCalorieAuthenticationServerHandler : AuthenticationHandler<LowCalorieAuthenticationServerOptions> 
{ 
    //Important this needs to be overriden, but just calls the base. 
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync() 
    { 
     return Task.FromResult<AuthenticationTicket>(null); 
    } 

    /// <summary>The apply response challenge async.</summary> 
    /// <returns>The <see cref="Task"/>.</returns> 
    protected override async Task ApplyResponseChallengeAsync() 
    { 
     if (this.Response.StatusCode != 401) 
     { 
      Task.FromResult<object>(null); 
      return; 
     } 

     var challenge = this.Helper.LookupChallenge(
      this.Options.AuthenticationType, 
      this.Options.AuthenticationMode); 
     if (challenge != null) 
     { 
      //OK in here you call the rediret to the 3rd party 
      //return a redirect to some endpoint 
     } 
     Task.FromResult<object>(null); 
     return; 
    } 
} 

反正注意如何倍率AuthenticateCoreAsync()只返回 回報Task.FromResult(NULL); 這是因爲我們不希望此中間件修改請求。 ApplyResponseChallengeAsync將等待挑戰並將您重定向到第三方登錄。如果您想創建某種本地令牌,您可以覆蓋InvokeAsync方法

您需要的第二個中間件是令牌/外部憑證驗證程序。這將以某種方式驗證用戶身份。在OWIN安全性中內置的本地不記名令牌的情況下,它簡單地對令牌進行反序列化,如果可以,並且令牌未過期,則對用戶進行驗證。因此,如果您想使用第三部分sso驗證令牌,例如google或任何其他內容,則可以在此處插入邏輯。在我的情況下,我不僅想打電話給第三方提供商以獲取用戶信息,但要檢查它們的令牌是否仍然適用於單次退出,並防止多個會話。

public class LowCalorieAuthenticationHandler : AuthenticationHandler<LowCalorieAuthenticationOptions> 
{ 

    //Going to give you the user for the request.. You Need to do 3 things here 
    //1. Get the user claim from teh request somehow, either froma header, request string, or cookie what ever you want 
    //2. validate the user with whatever user store or 3rd party SSO you want 
    //3. Generate a AuthenticationTicket to send to on to the request, you can use that to see if the user is valid in any Identity collection you want. 
    protected override async Task<AuthenticationTicket> AuthenticateCoreAsync() 
    { 




     //Good to throw in a point of override here.. but to keep it simple-ish 
     string requestToken = null; 
     string authorization = Request.Headers.Get("Authorization"); 

     //TOTAL FAKEOUT.. I am going to add a bearer token just so the simple sample works, but your client would have to provide this 
     authorization = "Bearer 1234567869"; 

     //STEP 1 
     if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) 
     { 
      requestToken = authorization.Substring("Bearer ".Length).Trim(); 
      return await FakeExternalBearer(requestToken); 
     } 

     return null; 
    } 

    private async Task<AuthenticationTicket> FakeExternalBearer(string token) 
    { 
     var authenticationType = Options.AuthenticationType; 
     //pretend to call extenal Resource server to get user //STEP 2 
     //CallExternal(token) 

     //Create the AuthTicket from the return.. I will fake it out 
     var identity = new ClaimsIdentity(
          authenticationType, 
          ClaimsIdentity.DefaultNameClaimType, 
          ClaimsIdentity.DefaultRoleClaimType); 

     identity.AddClaim(new Claim(ClaimTypes.NameIdentifier,"user1", null, authenticationType)); 
     identity.AddClaim(new Claim(ClaimTypes.Name, "Jon",null, authenticationType)); 

     var properties = new AuthenticationProperties(); 
     properties.ExpiresUtc = DateTime.UtcNow.AddMinutes(1); 
     properties.IssuedUtc = DateTime.UtcNow; 

     var ticket = new AuthenticationTicket(identity, properties); 
     return ticket; 
    } 
} 

好的,我們重寫AuthenticateCoreAsync,但我們現在確實做了一些事情。這是你的用戶認證。這是中間件的ACTIVE部分。請注意它需要返回一個有效的AuthenticationTicket。這將在每個請求上運行,所以要小心你打電話的頻率和頻率。 所以我在這裏有一個非常簡單的例子https://github.com/jzoss/LowCalorieOwin如果有人對更多細節感興趣,請詢問。我可以添加更多。我確實做得太難了,因爲現在我明白了,這很容易,但是如何做到這一點真的沒有好的例子。

1

你這樣做太難了。

而不是創建自己的承載身份驗證中間件,您應該更改默認OAuthBearerAuthenticationProvider

以下是在查詢字符串中發送令牌的示例。

//in Startup class 
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions 
{ 
    Provider = new QueryStringOAuthBearerProvider(), 
    //your settings 
}); 

//implementation 
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider 
{ 
    private const string AccessTokenQueryKey = "access_token"; 

    public override Task RequestToken(OAuthRequestTokenContext context) 
    { 
     //check if token found in the default location - "Authorization: Bearer <token>" header 
     if (string.IsNullOrEmpty(context.Token)) 
     { 
      var token = context.Request.Query.Get(AccessTokenQueryKey); 

      if (!string.IsNullOrEmpty(token)) 
      { 
       context.Token = token; 
      } 
     } 

     return Task.FromResult<object>(null); 
    } 
}