使用 B2C 生成元数据端点时,id_token_hint 参数签名验证失败

Posted

技术标签:

【中文标题】使用 B2C 生成元数据端点时,id_token_hint 参数签名验证失败【英文标题】:id_token_hint parameter failed signature validation when Using B2C to generate the metadata endpoints 【发布时间】:2021-12-11 09:17:03 【问题描述】:

我正在尝试使用 Azure B2C 设置类似系统的魔术链接。使用以下示例: 初级:https://github.com/azure-ad-b2c/samples/tree/master/policies/sign-in-with-magic-link

对于 sing B2C 来生成元数据端点: https://github.com/azure-ad-b2c/samples/tree/master/policies/invite#using-b2c-to-generate-the-metadata-endpoints

作为一个注释,我相信我曾经有过它的工作,但在清理之后我得到了错误:

提供的 id_token_hint 参数签名验证失败。请提供另一个令牌并重试。

我设置的步骤如下:

    通过 powershell 创建证书并获取指纹以在本地代码中使用 通过 MMC 使用 certmng 导出证书 所有任务/导出/下一步/是,导出私钥 个人信息交换 - PKCS(包括证书路径中的所有证书)(启用证书隐私) 安全(密码)随机生成的 25 个字符密码。 名称:id_token_hint_cert.pfx 浏览 Azure/B2C/身份体验框架/策略键 添加/选项:上传/名称:IdTokenHintCert/文件上传 id_token_hint_cert.pfx/密码:设置 3 中的密码

这是我尝试了 2 种不同设置的地方。第一个是设置一组自定义策略,以便我可以更新以下声明提供程序以将 issuer_secret 设置为 B2C_1A_IdTokenHintCert

<ClaimsProvider>
  <DisplayName>Token Issuer</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="JwtIssuer">
      <DisplayName>JWT Issuer</DisplayName>
      <Protocol Name="None" />
      <OutputTokenFormat>JWT</OutputTokenFormat>
      <Metadata>
        <Item Key="client_id">service:te</Item>
        <Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
        <Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="issuer_secret" StorageReferenceId="B2C_1A_IdTokenHintCert" />
        <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
      </CryptographicKeys>
      <InputClaims />
      <OutputClaims />
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

这是从 https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/tree/master/LocalAccounts 获取并更新给我的租户的一组政策,但大部分时间都没有。

我还尝试在我的主要自定义策略中更改 issuer_secret 并输出相同的错误。

进入我的代码: 这是我创业的重要部分:

public void ConfigureServices(IServiceCollection services)
    
        services.AddAuthentication(
            OpenIdConnectDefaults.AuthenticationScheme
        ).AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAdB2C"),"OpenIdConnect", "Cookies",true);

        services.AddControllersWithViews();
        services.AddRazorPages() 
            .AddMicrosoftIdentityUI();

        

        services.AddTransient<IClaimsTransformation, AppClaimsTransformations>();
    

这是我的主控制器,我在其中提交表单,创建令牌和链接,然后使用它作为立即运行端点重定向到该链接。 (我知道这不会结束工作,但需要先验证签名,然后才能继续。)

public class HomeController : Controller

    private static Lazy<X509SigningCredentials> SigningCredentials;
    private readonly AppSettingsModel _appSettings;
    private readonly IWebHostEnvironment HostingEnvironment;
    private readonly ILogger<HomeController> _logger;

    // Sample: Inject an instance of an AppSettingsModel class into the constructor of the consuming class, 
    // and let dependency injection handle the rest
    public HomeController(ILogger<HomeController> logger, IOptions<AppSettingsModel> appSettings, IWebHostEnvironment hostingEnvironment)
    
        _appSettings = appSettings.Value;
        this.HostingEnvironment = hostingEnvironment;
        this._logger = logger;

        // Sample: Load the certificate with a private key (must be pfx file)
        SigningCredentials = new Lazy<X509SigningCredentials>(() =>
        
            X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            certStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = certStore.Certificates.Find(
                                        X509FindType.FindByThumbprint,
                                        "***************************************",
                                        false);
            // Get the first cert with the thumb-print
            if (certCollection.Count > 0)
            
                return new X509SigningCredentials(certCollection[0]);
            

            throw new Exception("Certificate not found");
        );
    

    [HttpGet]
    public ActionResult Index(string Name, string email, string phone)
    

        if (string.IsNullOrEmpty(email))
        
            ViewData["Message"] = "";
            return View();
        

        string token = BuildIdToken(Name, email, phone);
        string link = BuildUrl(token);

        
        return Redirect(link);
    


    private string BuildIdToken(string Name, string email, string phone)
    
        string issuer = $"this.Request.Scheme://this.Request.Hostthis.Request.PathBase.Value/";

        // All parameters send to Azure AD B2C needs to be sent as claims
        IList<System.Security.Claims.Claim> claims = new List<System.Security.Claims.Claim>();
        claims.Add(new System.Security.Claims.Claim("name", Name, System.Security.Claims.ClaimValueTypes.String, issuer));
        claims.Add(new System.Security.Claims.Claim("email", email, System.Security.Claims.ClaimValueTypes.String, issuer));

        if (!string.IsNullOrEmpty(phone))
        
            claims.Add(new System.Security.Claims.Claim("phone", phone, System.Security.Claims.ClaimValueTypes.String, issuer));
        

        // Create the token
        JwtSecurityToken token = new JwtSecurityToken(
                issuer,
                "******************************************",
                claims,
                DateTime.Now,
                DateTime.Now.AddDays(7),
                HomeController.SigningCredentials.Value);

        // Get the representation of the signed token
        JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();

        return jwtHandler.WriteToken(token);
    

    private string BuildUrl(string token)
    
        string nonce = Guid.NewGuid().ToString("n");

        return string.Format("https://0.b2clogin.com/0.onmicrosoft.com/1/oauth2/v2.0/authorize?client_id=2&nonce=4&redirect_uri=3&scope=openid&response_type=id_token",
                "myTenant",
                "B2C_1A_SIGNIN_WITH_EMAIL",
                "************************************",
                Uri.EscapeDataString("https://jwt.ms"),
                nonce)
                    + "&id_token_hint=" + token;
    

   
    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    
        return View(new ErrorViewModel  RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier );
    

【问题讨论】:

【参考方案1】:

位置位置位置。

我正在调整我知道不应该这样做的基本配置文件。当我将更改应用到扩展文件时,一切都开始正常工作。

【讨论】:

以上是关于使用 B2C 生成元数据端点时,id_token_hint 参数签名验证失败的主要内容,如果未能解决你的问题,请参考以下文章

如何强制Azure Active Directory身份验证服务重新发出带有更新声明的id_token?

OpenID Connect 轻量级库

如何使用 B2C 和 Blazor 获取 JWT 不记名令牌

如何使用 id_token 从 Azure Function 应用程序获取 Azure access_token?

如何在头文件中使用授权编写路由/端点的单元测试?

我们真的需要在 OIDC 的隐式流中使用 id_token 吗?