0

编辑:我改变了我的方法。现在我正在使用 MessageHandlers。感谢 Raciel,他指出了挖掘的方向。

这些链接对我非常有用: MessageHandlers overview Using own Principal classes


我有一个 WebApi 项目,需要为其提供自定义授权。特殊令牌对象被添加到来自前端的每个请求。像这样的东西:

SendApiRequest: function (controller, action, data, successCallback, failureCallback) {
    var url = ROUTER.GetApiUrl(controller, action);

    data.Token = TOKEN;

    jQuery.ajax({
        type: 'POST',
        dataType: 'json',
        url: url,
        data: data,
        success: function (result) {
            if (typeof successCallback == 'function') {
                successCallback(result);
            }
        },
        error: function (result) {
            if (typeof failureCallback == 'function') {
                failureCallback(result);
            }
        }
    });}

我有一个 AuthorizationAttribute 并且我需要从请求中序列化 Token 对象。但找不到任何自动方法来做到这一点。

public class CustomAuthorizationAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(HttpActionContext context)
    {
        UserToken token = null;

        //HOW TO SERIALIZE token object from context?

    }
}

UserToken 类如下所示:

public class UserToken
{
    public Int64 TokenID;
    public int UserID;
    public string TokenValue;
    public string IP;
    public string Hash;

    public DateTime CreatedOn;
    public DateTime ActionOn;
}

所以问题是:如何从 HttpActionContext 序列化自定义对象?

谢谢你。

4

1 回答 1

2

这就是我在处理与您类似的案件时所做的。

Instead of creating your own Authorize attribute, you can create a MessageHandler which checks for the token and validates it on every request. This message handler is the responsible for populating the Principal in the current thread, so the Authorize attribute can work as expected allowing authorized clients to access the controller/action in question.

This is how my Authorization message handler looks like:

public class AuthMessageHandler : DelegatingHandler
{
    protected ITokenProvider TokenProvider { get; private set; }
    protected IPrincipalProvider PrincipalProvider { get; private set; }

    public AuthMessageHandler(ITokenProvider tokenProvider, IPrincipalProvider principalProvider)
    {
        TokenProvider = tokenProvider;
        PrincipalProvider = principalProvider;
    }


    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Identity identity = null;
        string token = ExtractToken(request);

        if (token != null && TokenProvider.Verify(token, out identity))
        {
            request.Properties.Add(Constants.IdentityKey, identity);
            var principal = PrincipalProvider.CreatePrincipal(identity);
            Thread.CurrentPrincipal = principal;
            HttpContext.Current.User = principal;
        }

        return base.SendAsync(request, cancellationToken);
    }


    private string ExtractToken(HttpRequestMessage request)
    {
        IEnumerable<string> tokenValues = null;
        if (request.Headers.TryGetValues(Constants.TokenHeaderKey, out tokenValues))
            return tokenValues.First();

        return null;
    }
}

Please note:

  1. Both TokenProvider and PrincipalProvider are injected here. The first is in charge of validating the token and if valid, return the identity data so it is available across the request.
  2. The IPrincipal provider just creates a GenericPrincipal that is then assigned to the Thread.CurrentPrincipal and to the context user (HttpContext.Current.User). This ensures that the Authorize attribute works later, when it checks for IsAuthenticated in the current Principal.
  3. In this case, I'm passing the token information in the headers, which I prefer. (You might need to authorize GET requests too)
  4. If you need to pass data from a message handler to a controller, you use the request.Properties, this is why I'm putting the Identity information there with request.Properties.Add(Constants.IdentityKey, identity); so it is available to the controller. There are several ways you can achieve this, but this dictionary is pretty much a cheap transport for this type of data.

Please let me know if you have any questions. This is actually simpler that it looks.

于 2013-08-19T21:01:45.793 回答