Basic WCF REST authentication for specific methods

I have quite a few RESTful methods (GET and POST) implemented in WCF 4.0. All of this works on SSL.

An example of some methods:

[OperationContract] [WebInvoke(UriTemplate = "Login?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] LoginResponse Login(LoginRequest request); [OperationContract] [WebInvoke(UriTemplate = "UpdateDetails?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] UpdateUserDetailResponse UpdateDetails(UpdateUserDetailRequest request); [OperationContract] [WebInvoke(UriTemplate = "GetDetails?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] UserDetailResponse GetDetails(UserDetailRequest request); 

I have looked through so many blogs and forums, and I still can’t find something that meets my requirements. I need to perform basic authentication using some of the methods, but not all. If you look at the examples above, I need to provide a username and password for the UpdateDetails and GetDetails methods, but not for the Login method. The username and password are then authenticated against the database. Is it possible to do something like this?

As a side note: these REST methods are called by many different mobile devices.

I looked at the following sites and they all implement basic REST authentication, but they cover all the methods described above.

Can I do what I want to do?

+6
source share
1 answer

I created the BasicAuthenticationInvoker class, which you associate with the methods you want to authenticate as follows:

  [OperationContract] [BasicAuthenticationInvoker] // this is the auth attribute! [WebInvoke(UriTemplate = "QuickQuote?", Method = "POST", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] QuickQuoteResponse QuickQuote(QuickQuoteRequest request); 

The actual class is as follows:

  public class BasicAuthenticationInvoker : Attribute, IOperationBehavior, IOperationInvoker { #region Private Fields private IOperationInvoker _invoker; #endregion #region IOperationBehavior Members public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) { _invoker = dispatchOperation.Invoker; dispatchOperation.Invoker = this; } public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { } public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { } public void Validate(OperationDescription operationDescription) { } #endregion #region IOperationInvoker Members public object Invoke(object instance, object[] inputs, out object[] outputs) { if (Authenticate("Client Name here")) return _invoker.Invoke(instance, inputs, out outputs); else { outputs = null; return null; } } public object[] AllocateInputs() { return _invoker.AllocateInputs(); } public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) { throw new NotSupportedException(); } public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) { throw new NotSupportedException(); } public bool IsSynchronous { get { return true; } } #endregion private bool Authenticate(string realm) { string[] credentials = GetCredentials(WebOperationContext.Current.IncomingRequest.Headers); if (credentials != null && credentials.Length == 2) { // do auth here var username = credentials[0]; var password = credentials[1]; // validate the username and password against whatever auth logic you have return true; // if successful } WebOperationContext.Current.OutgoingResponse.Headers["WWW-Authenticate"] = string.Format("Basic realm=\"{0}\"", realm); WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized; return false; } private string[] GetCredentials(WebHeaderCollection headers) { string credentials = WebOperationContext.Current.IncomingRequest.Headers["Authorization"]; if (credentials != null) credentials = credentials.Trim(); if (!string.IsNullOrEmpty(credentials)) { try { string[] credentialParts = credentials.Split(new[] {' '}); if (credentialParts.Length == 2 && credentialParts[0].Equals("basic", StringComparison.OrdinalIgnoreCase)) { credentials = Encoding.ASCII.GetString(Convert.FromBase64String(credentialParts[1])); credentialParts = credentials.Split(new[] {':'}); if (credentialParts.Length == 2) return credentialParts; } } catch { } } return null; } } 
+1
source

Source: https://habr.com/ru/post/916911/


All Articles