WebApi从HttpActionContext序列化对象

时间:2013-08-19 20:32:32

标签: c# javascript serialization asp.net-web-api authorization

编辑:我改变了方法。现在我正在使用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序列化自定义对象?

谢谢。

1 个答案:

答案 0 :(得分:2)

当我处理与你类似的案件时,这就是我所做的。

您可以创建 MessageHandler ,而不是创建自己的授权属性,该 MessageHandler 会检查令牌并在每次请求时对其进行验证。此消息处理程序负责填充当前线程中的 Principal ,因此Authorize属性可以按预期工作,允许授权客户端访问相关控制器/操作。

这就是我的授权消息处理程序的样子:

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;
    }
}

请注意:

  1. TokenProvider和PrincipalProvider都在这里注入。第一个负责验证令牌,如果有效,则返回身份数据,以便在请求中可用。
  2. IPrincipal提供程序只创建一个GenericPrincipal,然后将其分配给Thread.CurrentPrincipal和上下文用户(HttpContext.Current.User)。这可以确保Authorize属性在以后检查当前Principal中的IsAuthenticated时有效。
  3. 在这种情况下,我在标题中传递令牌信息,我更喜欢。 (您可能还需要授权GET请求)
  4. 如果需要将数据从消息处理程序传递到控制器,则使用request.Properties,这就是我将身份信息放在request.Properties.Add(Constants.IdentityKey,identity);所以它可供控制器使用。有几种方法可以实现这一点,但这种字典对于这类数据来说几乎是一种便宜的传输方式。
  5. 如果您有任何疑问,请与我们联系。这看起来更简单。