对如何在 Blazor App 中从 B2C 获取访问令牌感到困惑

Tjo*_*sta 10 azure azure-ad-b2c blazor blazor-server-side

我有一个配置了 B2C 身份验证的 Blazor 服务器端应用程序。这个应用程序将调用一个 webapi 来与我的服务进行任何数据交换。B2C 身份验证工作正常,直接从模板配置 B2C 身份验证是:

services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
            .AddAzureADB2C(options => { Configuration.Bind("AzureAdB2C", options); });
Run Code Online (Sandbox Code Playgroud)

这些声明只有我从我的登录策略返回的声明,没有任何我可以用来代表我的 Web api 进行身份验证的访问令牌(也用同一个 B2C 租户保护)。

我已经阅读了大约 100 个不同的文档,但在 blazor 的上下文中似乎没有任何意义。有没有人以前做过这件事可以说明一些问题?

一等奖是在用户第一次向 B2C 进行身份验证后请求访问令牌,然后将令牌保存在缓存中,以便在会话/浏览器打开或访问令牌有效时在 blazor 应用程序中用于任何 api 调用。

似乎这是正确的路径:https : //github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi/blob/master/TaskWebApp/Controllers/TasksController.cs但我什么我不明白的是:

  • 这是 Blazor 的正确方法吗?
  • 如何触发它以获取用户身份验证请求的访问令牌。我不清楚如何覆盖 B2C 身份验证构造函数。
  • 我可以在当前用户的声明中添加访问和刷新令牌,以便我可以在我的应用程序中全局使用 httpcontext 对象来获取执行我的 api 调用所需的令牌吗?
  • 上面文档中的代码当然在控制器中。希望将这种形式作为用户身份验证流程的一部分。
  • 似乎 B2C 身份验证的配置现在非常模板化......例如,我在哪里可以自定义身份验证的路由?我宁愿将用户定向到 /auth 或 /login 而不是 /AzureB2C/Login(为了掩盖明显的身份验证提供程序 url。我知道它会在地址栏中显示给用户......但是嘿......任何将非常感谢帮助将具体说明如何在 Blazor 服务器端处理此问题。

谢谢!

Oyv*_*tad 5

我在https://github.com/yberstad/BlazorAuth为您创建了一个带有 OpenId Connect 和 Blazor(服务器)的示例应用程序。它使用 SameSiteCookie 和 OpenId Connect。

  1. 在 appsettings.json 中,填写您的权限、ClientId 和 ClientSecret。
  2. 将 Azure 中的重定向 URI 配置为http://localhost:62438/signin-oidc/
  3. 在调试模式下启动应用程序
  4. 到了http://localhost:62438/api/openidconnect/login
  5. 使用 Azure 登录
  6. 到达http://localhost:62438/api/openidconnect/user,在 OpenIdConnectController.GetUser 操作中有一个断点,在那里您可以看到如何获取访问令牌。

如何获取访问和刷新令牌:

var accessToken = await HttpContext.GetTokenAsync("access_token");
var refreshToken = await HttpContext.GetTokenAsync("refresh_token");
Run Code Online (Sandbox Code Playgroud)

SameSiteCookie 信息:https ://brockallen.com/2019/01/11/same-site-cookies-asp-net-core-and-external-authentication-providers/

获取访问令牌:http : //docs.identityserver.io/en/latest/quickstarts/5_hybrid_and_api_access.html#using-the-access-token

将令牌存储在 SameSiteCookie 中使其仅对服务器可见,因此不会在客户端的不安全环境中保存和公开它。SameSiteCookie 对于 XSS 也是安全的。

希望这可以帮助。


Tjo*_*sta 4

我自己解决了这个问题。我的 AcquireTokenSilent 调用失败,因为调用它时缓存中没有用户,因此我必须确保在用户登录时将第一个条目添加到缓存中。我可以通过如下配置身份验证来实现此目的:

services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = AzureADB2CDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = AzureADB2CDefaults.OpenIdScheme;
            })
               .AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options))
               .AddCookie();

            services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
            {
                //Configuration.Bind("AzureAdB2C", options);
                options.ResponseType = Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectResponseType.CodeIdToken;
                options.Scope.Add("offline_access");
                options.Scope.Add("https://mytenant.onmicrosoft.com/api/api.read.write");

                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                options.Events.OnAuthorizationCodeReceived = async context =>
            {
                AzureADB2COptions opt = new AzureADB2COptions();
                Configuration.Bind("AzureAdB2C", opt);
                // As AcquireTokenByAuthorizationCodeAsync is asynchronous we want to tell ASP.NET core that we are handing the code
                // even if it's not done yet, so that it does not concurrently call the Token endpoint. (otherwise there will be a
                // race condition ending-up in an error from Azure AD telling "code already redeemed")
                context.HandleCodeRedemption();

                var code = context.ProtocolMessage.Code;
                string signedInUserID = context.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;

                IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder.Create(opt.ClientId)
                .WithB2CAuthority(opt.Authority)
                .WithRedirectUri(opt.RedirectUri)
                .WithClientSecret(opt.ClientSecret)
                .WithClientName("myWebapp")
                .WithClientVersion("0.0.0.1")
                .Build();
                new MSALStaticCache(signedInUserID, context.HttpContext).EnablePersistence(cca.UserTokenCache);

                try
                {
                    AuthenticationResult result = await cca.AcquireTokenByAuthorizationCode(opt.ApiScopes.Split(' '), code)
                        .ExecuteAsync();
                    context.HandleCodeRedemption(result.AccessToken, result.IdToken);

                }
                catch (Exception)
                {


                }

            };





            });
Run Code Online (Sandbox Code Playgroud)