开发者

How to set identity/username in ServiceAuthorizationManager?

I have a WCF 4.0 REST service on server side (hosted in IIS) and an Android client. The Android client sends an encrypted security token in a custom HTTP header in order to authenticate the user. I have implemented a custom ServiceAuthorizationManager which extracts the security token from the header. The token contains the username which I can read from the token:

public class MyAuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        var requestMessage = operationContext.RequestContext.RequestMessage;
        var requestProperty = (HttpRequestMessageProperty)requestMessage
            .Properties[HttpRequestMessageProperty.Name];
        var token = requestProperty.Headers["X-MyCustomHeader"];
        if (!string.IsNullOrEmpty(token))
        {
            var userName = GetUserNameFromToken(token);
            if (!string.IsNullOrEmpty(userName))
            {
                // How to save userName now so tha开发者_开发技巧t I can 
                // retrieve it in the service operations?
                return true;
            }
        }
        return false;
    }
}

Now, my problem is that I also need the name of the authenticated user in various service operations (mainly to access user profile data) and I was planning to retrieve it this way:

public void MyServiceOperation()
{
    string userName = OperationContext.Current
        .ServiceSecurityContext.PrimaryIdentity.Name;

    // check profile store for that userName and do something depending on
    // profile settings
}

How can I set this username in CheckAccessCore?

A very naive trial like this...

operationContext.ServiceSecurityContext.PrimaryIdentity.Name = userName;

...doesn't work because PrimaryIdentity.Name is readonly. I assume that more sophisticated code is required.


After some research I didn't find a way to set the identity in ServiceAuthorizationManager.CheckAccessCore. This method seems to be called too late in the processing pipeline when the user's identity is already set (possibly to "Anonymous" (IsAuthenticated is false)) and cannot be changed anymore. The ServiceAuthorizationManager is made for authorization, not authentication, therefore it's the wrong place to implement a custom authentication.

I've finally found three possible ways for my problem:

  1. As explained in the article linked in @TheCodeKing's answer, using the WCF REST Starter Kit provides the option to write a custom RequestInterceptor which hooks in early enough into the pipeline, allows access to the incoming request and allows to set the user's identity based on, for example, custom HTTP headers. Unfortunately the WCF REST Starter Kit is old (based on WCF 3.5) and the development has apparently been abandoned. Some of its features have been incorporated into WCF 4.0, but some have not, and the RequestInterceptor is among them. Nonetheless I've used this solution now and mixed the Microsoft.ServiceModel.Web assembly from the Starter Kit into my WCF 4.0 solution. It seems to work so far after a few simple tests.

  2. If the identity is not really necessary but only the user name, a simple "trick"/"hack" to write the user name into a new request header works (also in CheckAccessCore):

    // ...
    var userName = GetUserNameFromToken(token);
    if (!string.IsNullOrEmpty(userName))
    {
        requestProperty.Headers["X-UserName"] = userName;
        return true;
    }
    // ...
    

    And then in the service methods:

    public void MyServiceOperation()
    {
        string userName = WebOperationContext.Current.IncomingRequest
            .Headers["X-UserName"];
        // ...
    }
    
  3. Another and more low level option would be to write a custom HttpModule which intercepts the incoming request and sets the identity. An example how this could look like is here from Microsoft Pattern & Practices team (see the "HTTP Module Code" example in the mid of the article).


Take a look at this article. It has examples of setting up the IAuthorizationPolicy instance. By creating your own implementation you can control the creation of the IPrincipal and IIdentity instances which are passed around in the context. It's all hooked in from a service interceptor.

internal class AuthorizationPolicyFactory
{
   public virtual IAuthorizationPolicy Create(Credentials credentials)
   {
      var genericIdentity = new GenericIdentity(credentials.UserName);
      var genericPrincipal = new GenericPrincipal(genericIdentity,
                                                  new string[] { });
      return new PrincipalAuthorizationPolicy(genericPrincipal);
   }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜