1

注意:我在下面的代碼註釋中散佈了很多問題。我也需要這些答案。我在哪裏處理webapi中的自定義身份驗證和授權?

我已閱讀(以及許多其他)下面的文章:

我想爲我的網絡API有使用授權的標頭中發送認證頭。我想將這個頭文件填充到名爲AuthenticationToken的c#類中。然後,當我在做參數綁定時,我想檢索此前創建的AuthenticationToken對象,並將其傳遞給我的控制器操作。舉例來說,如果我有以下控制器

public class MyServiceController : ApiController { 

    readonly ISecurityService _security; 
    readonly IMyService _myService; 

    // constructor values are injected 
    public MyServiceController(ISecurityService security, IMyService myService) { 
     _security = security; 
     _myService = myService; 
    } 

    public SomeData GetASpecificItem(AuthenticationToken token, int id) { 

     if (_security.IsAuthorized(token, Permissions.Read)) { 
      return myService.DoStuffToGetSomeData(token); 
     } else { 
      var msg = new HttpResponseMessage(HttpStatusCode.Forbidden); 
      throw new HttpResponseException(msg); 
     } 
    } 
} 

和下面的參數綁定類

public class AuthenticationTokenParameterBinding 
    : HttpParameterBinding { // do I need to inherit from a different class? 

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, 
              HttpActionContext actionContext, 
              CancellationToken cancellationToken) { 
    try { 

     AuthenticationToken token; // UPDATED: how can i get this from the data 
           //   available from inside this method? 

     SetValue(actionContext, token); 

     // is this the correct task to return on successfull parameter binding? 
     return base.ExecuteBindingAsyn(metadataProvider, actionContext, cancellationToken); 

    } catch { 
     return Task<HttpResponseMessage>.Factory.StartNew(() => { 
     var hpm = new HttpResponseMessage(HttpStatusCode.Unauthorized); 
     hpm.Headers.Add("WWW-Authenticate","MyCustomScheme"); 
     return hpm; 
     }); 
    } 
    } 
} 

如果這兩個都正確實施,那麼控制器會自動獲取被授權期間創建的AuthenticationToken實例。

我不知道在這個過程之前認證的地方。我也不知道如何在身份驗證和授權之間傳遞對象。

UPDATE: 我不能使用自定義AuthorizeAttribute,因爲授權可以是針對對象:

public SaveResponse Save(AuthenticationToken user, SomeObjectThatNeedsToBeSaved obj) { 

    // NOTE: permissions are checked between the object and the user, not a role 

    if (_security.IsAuthorized(user, obj, Permission.Modify, Permission.Create)) { 

    // NOTE: other permissions we don't know about may need to be checked in the service call 

    return new SaveResponse { 
     Success = ISomeService.Save(user, obj); // bool return value 
    } 
    } else { 
    // return 403 Forbidden  } 
} 

我需要通過令牌控制器動作,但我還需要驗證令牌傳遞給控制器​​之前。由於基於這一切並不一定作用,我不知道怎樣才能從自定義AuthorizeAttribute

回答

1

的內部驗證我已經使用了自定義AuthorizeAttribute處理的Web API身份驗證和授權。此屬性用作篩選器,並在請求到達Web API方法之前處理該請求。在覆蓋OnAuthorize方法,你可以返回HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)如果驗證失敗和HttpResponseMessage(System.Net.HttpStatusCode.Forbidden)如果授權失敗,使客戶端可以兩種類型的區分的錯誤。除了自定義AuthorizeAttribute我實現了自定義MembershipProviderRoleProvider來處理我的特定安全要求和自定義數據庫模式。

我使用基本身份驗證來傳遞憑據進行授權。這將憑據放在標題中。通過使用jQuery ajax函數的事件處理程序之前的beforeSend來做到這一點非常簡單。這裏是一個如何做到這一點的例子。

getAuthorizationHeader = function (username, password) { 
     var authType; 
     var up = $.base64.encode(username + ":" + password); 
     authType = "Basic " + up; 
    }; 
    return authType; 
}; 

    $.ajax({ 
     url: _url, 
     data: _data, 
     type: _type, 
     beforeSend: function (xhr) { 
      xhr.setRequestHeader("Authorization", getAuthorizationHeader(username, password)); 
     }, 
     success: ajaxSuccessHandler, 
     error: ajaxErrHandler 
    }); 

這將編碼在標題中發送的用戶名/密碼。請注意,由於編碼很容易解碼,因此這不足以依賴編碼。您仍希望使用HTTPS/SSL來確保通過線路發送的信息是安全的。

在Web API方面,您可以自定義AuthorizeAttribute從頭獲取憑證,解碼它們並執行授權過程。 Web API使用了與控制器相對的獨立的AuthorizeAttribute。在創建自定義AuthorizeAttribute時,請務必使用System.Web.Http.AuthorizeAttribute作爲您的基類。他們有不同的行爲。控制器將要重定向到登錄頁面,而Web API的則返回指示成功或失敗的HTTP代碼。如果授權無法區分由於授權導致的失敗而不是身份驗證,則我會返回Forbidden的HTTP代碼,以便客戶端可以做出相應的反應。

以下是從標題中獲取證書的示例方法,該證書可用於自定義AuthorizeAttribute

private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password) 
    { 
     bool gotIt = false; 
     username = string.Empty; 
     password = string.Empty; 
     IEnumerable<string> headerVals; 
     if (actionContext.Request.Headers.TryGetValues("Authorization", out headerVals)) 
     { 
      try 
      { 
       string authHeader = headerVals.FirstOrDefault(); 
       char[] delims = { ' ' }; 
       string[] authHeaderTokens = authHeader.Split(new char[] { ' ' }); 
       if (authHeaderTokens[0].Contains("Basic")) 
       { 
        string decodedStr = SecurityHelper.DecodeFrom64(authHeaderTokens[1]); 
        string[] unpw = decodedStr.Split(new char[] { ':' }); 
        username = unpw[0]; 
        password = unpw[1]; 
       } 
       gotIt = true; 
      } 
      catch { gotIt = false; } 
     } 

     return gotIt; 
    } 

這裏是解碼在這個方法中使用的標題數據的代碼。

public static string DecodeFrom64(string encodedData) 
    { 

     byte[] encodedDataAsBytes 

      = System.Convert.FromBase64String(encodedData); 

     string returnValue = 

      System.Text.Encoding.ASCII.GetString(encodedDataAsBytes); 

     return returnValue; 

    } 

一旦您擁有用戶名和密碼,您就可以執行授權過程並將相應的HTTP代碼返回給客戶端進行處理。

您可以使用自定義令牌執行類似的過程,或者如果您不想保留密碼/用戶名存儲在客戶端中,則可以利用來回傳遞的Cookie。

+0

我無法使用基於角色的安全性。此方法不起作用。這就是爲什麼我試圖以我提出的問題的方式來做到這一點。 –

+0

此方法不排除基於角色的授權方法。如果你不使用角色,你在授權什麼?針對物體的 –

+0

,例如該用戶是否具有對xyz對象的修改權限?另外,我的問題是關於認證,而不是授權。授權在代碼中完成。這就是爲什麼我需要方法簽名中的身份驗證令牌。 –