【问题标题】:The provided anti-forgery token was meant for a different claims-based user than the current user - Token Authentication提供的防伪令牌适用于与当前用户不同的基于声明的用户 - 令牌身份验证
【发布时间】:2018-08-01 08:37:35
【问题描述】:

我当前的身份验证过程如下所示。我有一个使用UseOAuthBearerAuthentication 生成令牌的Auth API。在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);

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

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;

现在,在我的资源 API 中,我已经从 cookie 中读取身份验证令牌并将其设置为 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");
            }
        }
    }

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

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

编辑:所以看来我在TokenEndpointResponse(OAuthTokenEndpointResponseContext context) 中生成我的XSRF 令牌 context.Identity 使用经过身份验证的User 设置,但是HttpContext.Current.Usernull。尽管此处生成的 XSRF 令牌在技术上是有效的,但我认为它们使用的是来自 HttpContext 的 null。如果我生成 XSRF 令牌是一个单独的带有 [Authorize] 的 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;
}

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

【问题讨论】:

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


    【解决方案1】:

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

    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.");
            }
    

    【讨论】:

    • 欢迎来到 Stack Overflow。请至少添加一些解释为什么这行代码会解决问题,以便提问者和任何其他有类似问题的程序员可以更好地理解发生了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 2020-05-31
    • 2015-02-01
    • 2016-03-19
    • 2023-04-10
    • 2013-12-18
    相关资源
    最近更新 更多