You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨项目传递AntiforgeryToken失败问题求助

跨项目反伪造令牌验证失败问题

项目结构

  • Project A:带有扩展功能的Duende Identity Server
  • Project B:使用Project A进行身份认证的Web客户端

通用配置

两个项目均默认启用:

  • AuthorizeFilter:要求请求必须经过授权
  • AutoValidateAntiforgeryTokenAttribute:要求请求必须携带反伪造令牌(AntiforgeryToken)

需求

此前所有交互均正常运行,需要在Project B中创建一个已授权的端点,调用Project A中的接口以生成自定义令牌。

Project A测试端点完整代码

[Route("ProjectAController/RequestToken")]
[HttpPost]
public async Task<IActionResult> RequestToken()
{
    string antiForgeryInputValue = String.Empty;
    string antiForgeryCookieValue = String.Empty;
    string antiForgeryCookieKey = String.Empty;
    var identityPath = _configuration["ProjectA_Link"];

    bool getFromIdentityServer = true;
    if (getFromIdentityServer)
    {
        using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
        {
            var response = await accountClient.GetAsync($"{identityPath}/Account/Login");
            var content = await response.Content.ReadAsStringAsync();
            IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
            var rawAntiForgeryCookie = cookies.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
            var match = Regex.Match(content, "name=\"__RequestVerificationToken\" type=\"hidden\" value=\"(.*?)\"");
            if (match.Success)
                antiForgeryInputValue = match.Groups[1].Value;
            var cookieAnti = SetCookieHeaderValue.Parse(rawAntiForgeryCookie);
            antiForgeryCookieValue = cookieAnti.Value.ToString();
            antiForgeryCookieKey = cookieAnti.Name.ToString();
        }
    }
    else
    {
        var antiForgeryHeaderTokenKey = Request.Form.FirstOrDefault(f => f.Key.StartsWith("__RequestVerificationToken")).Key;
        antiForgeryInputValue = Request.Form[antiForgeryHeaderTokenKey].ToString();
        antiForgeryCookieKey = Request.Cookies.Keys.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
        antiForgeryCookieValue = Request.Cookies[antiForgeryCookieKey];
    }

    var cookieDommainBaseAddress = new Uri(_configuration["ProjectA_Link"]);
    var container = HttpContext.RequestServices.GetService<CookieContainer>();
    container.Add(cookieDommainBaseAddress, new Cookie("idsrv", Request.Cookies["idsrv"]));
    container.Add(cookieDommainBaseAddress, new Cookie("idsrv.session", Request.Cookies["idsrv.session"]));
    container.Add(cookieDommainBaseAddress, new Cookie(antiForgeryCookieKey, antiForgeryCookieValue));

    using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
    {
        var dataToPost = new List<KeyValuePair<string, string>>() { { new KeyValuePair<string, string>("__RequestVerificationToken", antiForgeryInputValue) } };
        var content = new FormUrlEncodedContent(dataToPost);

        var result = await accountClient.PostAsync($"{identityPath}/Authentication/GenerateToken", content);
        result.EnsureSuccessStatusCode();
        if (result.IsSuccessStatusCode)
        {
            var contentResult = await result.Content.ReadAsStringAsync();
            var tokenGeneration = JsonSerializer.Deserialize<TokenGenerationResult>(contentResult, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
            if (tokenGeneration != null)
                return RedirectToAction("AuthStatus", new { referenceToken = tokenGeneration.ReferenceToken, refreshToken = tokenGeneration.RefreshToken });
        }
    }

    return RedirectToAction("AuthStatus");
}

两种尝试方案及对应代码

方案1:从Project A登录页获取反伪造Cookie和令牌

if (getFromIdentityServer)
{
    using (var accountClient = _httpClientFactory.CreateClient("IDPClient2"))
    {
        var response = await accountClient.GetAsync($"{identityPath}/Account/Login");
        var content = await response.Content.ReadAsStringAsync();
        IEnumerable<string> cookies = response.Headers.SingleOrDefault(header => header.Key == "Set-Cookie").Value;
        var rawAntiForgeryCookie = cookies.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
        var match = Regex.Match(content, "name=\"__RequestVerificationToken\" type=\"hidden\" value=\"(.*?)\"");
        if (match.Success)
            antiForgeryInputValue = match.Groups[1].Value;
        var cookieAnti = SetCookieHeaderValue.Parse(rawAntiForgeryCookie);
        antiForgeryCookieValue = cookieAnti.Value.ToString();
        antiForgeryCookieKey = cookieAnti.Name.ToString();
    }
}

方案2:从Project B当前请求中获取反伪造Cookie和令牌

else
{
    var antiForgeryHeaderTokenKey = Request.Form.FirstOrDefault(f => f.Key.StartsWith("__RequestVerificationToken")).Key;
    antiForgeryInputValue = Request.Form[antiForgeryHeaderTokenKey].ToString();
    antiForgeryCookieKey = Request.Cookies.Keys.FirstOrDefault(c => c.StartsWith(".AspNetCore.Antiforgery"));
    antiForgeryCookieValue = Request.Cookies[antiForgeryCookieKey];
}

报错信息

两种方案均在result.EnsureSuccessStatusCode();处触发异常:

方案1异常信息

[23:55:39 信息] Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter
反伪造令牌验证失败。提供的反伪造令牌属于另一个基于声明的用户,与当前用户不匹配。
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: 提供的反伪造令牌属于另一个基于声明的用户,与当前用户不匹配。
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
在 Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)

方案2异常信息

[00:33:27 信息] Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter
反伪造令牌验证失败。无法解密反伪造令牌。
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: 无法解密反伪造令牌。
---> System.Security.Cryptography.CryptographicException: 载荷无效。
在 Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData)
在 Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment1 ciphertext, ArraySegment1 additionalAuthenticatedData)
在 Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
在 Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
--- 内部异常堆栈跟踪结束 ---
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.DeserializeTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet, AntiforgeryToken& cookieToken, AntiforgeryToken& requestToken)
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateTokens(HttpContext httpContext, AntiforgeryTokenSet antiforgeryTokenSet)
在 Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
在 Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)


内容的提问来源于stack exchange,提问作者Erick Asto Oblitas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:23:15