提供的防伪令牌适用于与当前用户不同的基于声明的用户 - 令牌身份验证

时间:2018-02-21 16:57:47

标签: security asp.net-identity owin csrf claims-based-identity

我当前的身份验证过程如下所示。我有一个Auth API,可以使用UseOAuthBearerAuthentication生成令牌。在GrantResourceOwnerCredentials内生成令牌后,我将Identity.Name设置为identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.UserName));

我想将我的令牌存储在HttpOnly Cookie中,因此TokenEndpointResponse(OAuthTokenEndpointResponseContext context) 我将其保存为Cookie,但我还需要阻止XSRF,因此我也会在其中生成XSRF令牌。

string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);

如果我查看Identity中的当前OAuthTokenEndpointResponseContext context上下文,Identity.Name已设置,那么它应该使用此名称生成XSRF令牌。 但是 HttpContext.Current.User.Identitynull在我的两个API中我也设置了

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

现在在我的Resource API中,我已经处理了从cookie中读取auth令牌并将其设置为Authorization标头的问题。这很好。然后,我创建了自己的XSRF属性,验证XSRF令牌。

public class ValidateAntiForgery : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            try
            {
                string cookieToken = "";
                string formToken = "";

                IEnumerable<string> tokenHeaders;
                if (actionContext.Request.Headers.TryGetValues("X-XSRF-TOKEN", out tokenHeaders))
                {
                    string[] tokens = tokenHeaders.First().Split(':');
                    if (tokens.Length == 2)
                    {
                        cookieToken = tokens[0].Trim();
                        formToken = tokens[1].Trim();
                    }
                }
                AntiForgery.Validate(cookieToken, formToken);
            }
            catch(Exception e)
            {

                actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Bad Request");
            }
        }
    }

检查Identity中的actionContext,一切都已设置且用户已通过身份验证。但是,AntiForgery.Validate(cookieToken, formToken);会抛出异常,如下所示。我看了很多其他的例子,但我找不到解决方案。

  

System.Web.Mvc.HttpAntiForgeryException:'提供的防伪   令牌适用于与当前用户不同的基于声明的用户   用户'。

编辑:因此,我似乎在XSRF生成TokenEndpointResponse(OAuthTokenEndpointResponseContext context)令牌的位置 context.Identity是使用经过身份验证的User设置的,但HttpContext.Current.Usernull。尽管此处生成的XSRF令牌在技术上是有效的,但我认为它们使用HttpContext中的空值。如果我使用[授权]生成XSRF令牌是单独的GET请求,以便HttpContext.Current.User不是null,那么AntiForgery.Validate工作正常。

我希望使用身份验证令牌返回XSRF令牌,但我不知道该怎么做。如何设置HttpContext.Current.User.Identity

编辑2:所以我能够用hacky方式解决问题。当我想生成XSRF令牌时,我调用以下函数。

[Authorize]
public string generateXSRFToken(ClaimsIdentity identity)
{
        HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(identity, new string[0]);
        string cookieToken, formToken;
        AntiForgery.GetTokens(null, out cookieToken, out formToken);

        return cookieToken + ":" + formToken;
}

它有效!但它很难看,我想要一种更优雅的方式。

1 个答案:

答案 0 :(得分:0)

这应该可以解决您的问题:

var returnUrl = Request.QueryString["ReturnUrl"];
    if (returnUrl.IsEmpty()) {
        // Some external login providers always require a return URL value
        returnUrl = Href("~/");
    }
if (WebSecurity.Login(email, password, rememberMe))
        {
            Context.RedirectLocal(returnUrl);
            return;
        }
        else
        {
            ModelState.AddFormError("The user name or password provided is incorrect.");
        }