2016-07-22 65 views
0

我想就.NET Web API項目中的角色和作用域之間的區別做一個更清晰的描述。這比其他任何方面都更具有最佳方法的問題,我發現自己對如何最好地授權希望訪問我的API的用戶有點困惑。我來自.NET MVC背景,所以我熟悉角色,我想知道是否同樣的方法適用於Web API框架。我很難將範圍放在圖片中,以及如何使用它們來允許使用特定客戶端ID的用戶訪問。範圍與訪問權限類似嗎?爲了說明我的困惑,讓我們用這個例子:.Net Web API 2,OWIN和OAuth:範圍和角色。有什麼區別?

Client A 
Native app: displays event calendar 
Role: Event 
User login required? No 
Allowed scopes: Read events 

Client B 
Web app: shows next upcoming event, displays registrant names 
Role: Event 
User login required? Yes 
Allowed scopes: Read events, read registrants 

Client C 
Native app: registers a person for an event 
Role: Registrant 
User login required? Yes 
Allowed scopes: Read events, read registrants, write registrants 

基本上我想知道如果我的上述使用範圍的是正確的,什麼是最好的辦法是給予資源所有者憑證。我正在使用基於令牌的身份驗證,如Taiseers tutorial中所述。下面是我目前不完全的代碼片段,將採取的確認(validate)要求照顧客戶端和範圍:

public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
{ 
    ApiClient client = null; 
    string clientId = string.Empty; 
    string clientSecret = string.Empty; 

    if (!context.TryGetBasicCredentials(out clientId, out clientSecret)) 
     context.TryGetFormCredentials(out clientId, out clientSecret); 

    if (context.ClientId == null) 
    { 
     context.Validated(); 
     context.SetError("invalid_clientId", "ClientId should be sent."); 
     return Task.FromResult<object>(null); 
    } 

    using (ApiClientRepo _clientRepo = context.OwinContext.GetUserManager<ApiClientRepo>()) 
    { 
     client = _clientRepo.FindClient(context.ClientId); 
    } 

    if (client == null) 
    { 
     context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId)); 
     return Task.FromResult<object>(null); 
    } 

    // Validate client secret 

    if (string.IsNullOrWhiteSpace(clientSecret)) 
    { 
     context.SetError("invalid_secret", "Client secret should be sent."); 
     return Task.FromResult<object>(null); 
    } 
    else 
    { 
     WPasswordHasher passwordHasher = new WPasswordHasher(); 
     PasswordVerificationResult passwordResult = passwordHasher.VerifyHashedPassword(client.SecretHash, clientSecret); 

     if (passwordResult == PasswordVerificationResult.Failed) 
     { 
      context.SetError("invalid_secret", "Client secret is invalid."); 
      return Task.FromResult<object>(null); 
     } 
    } 

    if (!client.Active) 
    { 
     context.SetError("invalid_clientId", "Client is inactive."); 
     return Task.FromResult<object>(null); 
    } 

    context.OwinContext.Set<int>("as:clientRepoId", client.Id); 
    context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin); 
    context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString()); 

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

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
{ 
    IApiUser user = null; 
    string scope = null; 

    // Get parameters sent in body 
    Dictionary<string, string> body = context.Request.GetBodyParameters(); 

    // Get API scope 
    body.TryGetValue("scope", out scope); 

    if (scope == null) 
    { 
     context.Validated(); 
     context.SetError("invalid_scope", "Invalid requested scope."); 
     return; 
    } 

    var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); 

    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });  

    // At this point I got the requested scope. 
    // What should I do with it? 

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

    // create claims identity based on user info 
    ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType); 
    identity.AddClaim(new Claim(ClaimTypes.Name, user.FirstName + " " + user.LastName)); 
    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Username)); 
    identity.AddClaim(new Claim(ClaimTypes.Role, scope)); 

    var props = new AuthenticationProperties(new Dictionary<string, string> 
     { 
      { 
       "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId 
      }, 
      { 
       "userName", context.UserName 
      } 
     }); 

    var ticket = new AuthenticationTicket(identity, props); 
    context.Validated(ticket); 
} 

提前感謝所有的想法,建議和想法!

回答

3

在我的視角範圍內定義資源。 基本上,請求的挑戰是「可能客戶端(=應用程序)以您的名義訪問資源x」?

其中x是API提供的任何資源。 我在一個項目中使用了一個方便,其中一個作用域可以是特定於資源CRUD操作的項目。例如scope = tweets.read或tweets.create。

擁有一個作用域的令牌不會給客戶端許可。該權限基於這樣一個事實,即用戶有權執行該操作,並讓該客戶端的令牌中有正確的資源範圍。當然,用戶權限可以基於角色,例如來賓或管理員等。

因此理論上,用戶可以授予對其沒有權限的範圍(資源)的訪問權限。

令牌的生命週期爲20分鐘,如果您基於訪問令牌中的任何值創建了權限,則該令牌不會在令牌生存期內被撤銷或更改。

+0

感謝您的解釋。我明白,就你而言,你使用範圍作爲每個資源的權限,所以非常精細。我看了一下[Google的作用域文檔](https://developers.google.com/identity/protocols/googlescopes),看起來你可以像他們那樣做。那麼如何驗證請求是否具有資源x的適當範圍?你有自定義操作過濾器來做到這一點? – Sebbo

+0

我不會說它是一個許可持續,也許是一個客戶端訪問用戶資源的權限行爲。 事實上,我已經使用自定義過濾器驗證了範圍,並在每個WebApi方法上定義了具有所需範圍的自定義屬性。 – Max

+0

啊,是的,這是有道理的。我相信我現在對Web API的作用域和角色有更清晰的瞭解。我在想自定義過濾器來檢查所需的範圍。謝謝! – Sebbo

相關問題