2017-07-14 68 views
2

使用Owin + Oauth2 + Identity2。Web API2身份2承載令牌許可更改

我有一個網絡Api與默認的基本身份驗證設置,我已經修改。

我startup.cs部分類

public void ConfigureAuth(IAppBuilder app) 
    { 
     // Enable the application to use a cookie to store information for the signed in user 
     // and to use a cookie to temporarily store information about a user logging in with a third party login provider 
     app.UseCookieAuthentication(new CookieAuthenticationOptions()); 
     app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);//TODO: prob wont need this 

     // Configure the application for OAuth based flow 
     PublicClientId = "self"; 

     OAuthOptions = new OAuthAuthorizationServerOptions 
     { 
      TokenEndpointPath = new PathString("/Token"), 
      Provider = new ApplicationOAuthProvider(PublicClientId), 
      AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),//TODO: prob wont need this 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), 
      // In production mode set AllowInsecureHttp = false 
      AllowInsecureHttp = true //TODO: set debug mode 
     }; 

     // Token Generation 
     app.UseOAuthBearerTokens(OAuthOptions); 
    } 

我startup.cs類偏在根

public void Configuration(IAppBuilder app) 
    { 
     HttpConfiguration config = new HttpConfiguration(); 

     ConfigureAuth(app); 

     WebApiConfig.Register(config); 
     app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); 
     app.UseWebApi(config); 
    } 

我applicationOAuthProvider.cs

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     //get user 
     var service = new CarrierApi.CarrierManagementClient(); 
     var result = service.LoginAsync(context.UserName, context.Password); 
     var user = result.Result.Identity; 

     //TODO: log stuff here? i.e lastlogged etc? 

     if (user == null) 
     { 
      context.SetError("invalid_grant", "The user name or password is incorrect."); 
      return; 
     } 

     ClaimsIdentity oAuthIdentity = user; 
     ClaimsIdentity cookiesIdentity = user; 

     AuthenticationProperties properties = CreateProperties(user.GetUserName()); 
     AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); 
     context.Validated(ticket); 
     context.Request.Context.Authentication.SignIn(cookiesIdentity); 
    } 

正如你可以看到我通過對現有數據庫的wcf調用來獲取身份。當使用郵遞員時,我得到/令牌url並獲得我的不記名令牌,在下一個請求中,我將它傳遞給頭並調用我的控制器方法。

[Authorize(Roles = "Templates_Access")] 
    public string Post([FromBody]string value) 
    { 
     return "woo"; 
    } 

這很好,如果用戶有權限,它不會允許訪問,如果他們這樣做。

但是,如果我去我們的網站,使用相同的wcf和數據庫,並更改用戶權限,如果我發送郵遞員相同的請求它仍然允許訪問,即使我也刪除了該用戶分配的角色的權限。

我如何確保在每次請求時「刷新」或再次檢查權限?

+0

您想調出您的WCF服務以獲取每個請求嗎? – DavidG

+0

以及我需要檢查權限,這是在數據庫上設置的,WCF是唯一的訪問我們的數據庫。基本上我需要一種方式來檢查權限沒有改變,如果他們已然後更新會話或任何其他事情,以便授權工作 – lemunk

回答

3

在GrantResourceOwnerCredentials方法中,登錄時登錄的用戶的每個角色都作爲聲明在登錄時存儲在不記名令牌中。如果請求必須被授權,則通過AuthorizationFilter的默認實現在存儲在不記名令牌中的列表上搜索角色;所以如果你改變用戶的權限,你需要一個新的登錄名。

這種行爲尊重一個問題的REST架構的無狀態contraint,如Fielding在他的dissertation寫道,而且這是性能和安全性

之間的良好平衡。如果你需要一個不同的行爲有一個以上的可能性。

刷新令牌

你可以使用刷新令牌,實現applicationOAuthProvider類的GrantRefreshToken方法;您可以檢索刷新的用戶權限並創建一個新的訪問令牌;這是一篇很好的學習文章how

請記住:在客戶端

  • 沒有實時影響

    • 更多的複雜性;你必須等待訪問令牌到期
    • 如果訪問令牌的壽命短,你必須經常(即使用戶不會更改權限)來更新它,否則使用壽命長不能解決問題

    檢查權限的每個請求

    可以實現自定義AuthorizationFilter並在數據庫中檢查用戶的權限,但它是一個緩慢的解決方案。

    緩存和登錄會話

    您可以生成一個用戶會話的在GrantResourceOwnerCredentials方法每次登錄鍵(如GUID),並將其存儲在承載令牌的要求。您必須使用兩個索引將用戶會話密鑰和userId存儲在緩存系統(如Redis)中。 Redis的官方文檔解釋how

    當用戶的permessions被改變,你可以無效的高速緩存系統,用戶的每一個會議,由用戶id

    搜索可以實現自定義AuthorizationFilter併爲您在高速緩存每個請求如果會話有效,按用戶會話密鑰進行搜索。

    注意:這將違反無國籍限制,你的架構不會問題的REST


    在這裏你可以找到標準實施AuthorizaAttribute filter。 您可以創建自定義篩選器,擴展AuthorizeAttribute並覆蓋IsAuthorized方法。

    最有可能有其他方式,但多久更改一次用戶的權限?在許多系統中,在安全性是第一要求的系統中,如果在活動會話期間更改用戶的權限配置,則需要新的登錄才能激活新的用戶。 您確定需要修改此標準行爲嗎?

    如果您是這樣,我建議使用緩存系統的解決方案。

  • +0

    謝謝你的信息,所以你說的點身份緩存層,然後授權過濾器應該調用緩存檢查 – lemunk

    +0

    什麼是刷新令牌?它是否會再次呼叫身份以更新結果? – lemunk

    +0

    你必須自己實現刷新令牌的機制,以便刷新用戶的權限。我會編輯我的答案,以便更詳細。 –

    相關問題