对如何在 Blazor App 中从 B2C 获取访问令牌感到困惑
Posted
技术标签:
【中文标题】对如何在 Blazor App 中从 B2C 获取访问令牌感到困惑【英文标题】:Confused on how to get access tokens from B2C in Blazor App 【发布时间】:2020-03-18 00:04:47 【问题描述】:我有一个配置了 B2C 身份验证的 Blazor 服务器端应用程序。这个应用程序将调用 webapi 来与我的服务进行任何数据交换。 B2C 身份验证工作正常,直接从模板配置 B2C 身份验证是:
services.AddAuthentication(AzureADB2CDefaults.AuthenticationScheme)
.AddAzureADB2C(options => Configuration.Bind("AzureAdB2C", options); );
声明仅包含我从登录策略返回的声明,没有任何访问令牌可用于代表我的 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 的配置现在似乎非常模板化...例如,我可以在哪里自定义 auth 的路由?我宁愿将用户定向到 /auth 或 /login 而不是 /AzureB2C/Login (为了掩盖明显的身份验证提供程序 url。我知道它会在地址栏中显示给用户......但是嘿......任何将非常感谢您提供有关如何在 Blazor 服务器端处理此问题的具体帮助。谢谢!
【问题讨论】:
有任何见解的人吗? 【参考方案1】:我在这里 https://github.com/yberstad/BlazorAuth 为您创建了一个带有 OpenId Connect 和 Blazor(服务器)的示例应用程序。它使用 SameSiteCookie 和 OpenId 连接。
-
在appsettings.json中,填写你的Authority、ClientId和ClientSecret。
在 Azure 中将重定向 URi 配置为 http://localhost:62438/signin-oidc/
在调试模式下启动应用
转到http://localhost:62438/api/openidconnect/login
使用 Azure 登录
转到http://localhost:62438/api/openidconnect/user,在 OpenIdConnectController.GetUser 操作中有一个断点,在那里您可以看到如何获取访问令牌。
如何获取访问和刷新令牌:
var accessToken = await HttpContext.GetTokenAsync("access_token");
var refreshToken = await HttpContext.GetTokenAsync("refresh_token");
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 也是安全的。
希望这会有所帮助。
【讨论】:
您不应该在服务器端应用程序中使用 HttpContext。 所以为了在 Blazor 服务器中获取用户的访问令牌,我必须将它们发送到控制器吗?这似乎很奇怪。我觉得我错过了什么或误解了你在做什么。【参考方案2】:我自己解决了这个问题。我的 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)
;
);
【讨论】:
我认为你在这里做了很多工作。我有相同的设置(连接到 B2C 的 Balzor 服务器端应用程序)并且不需要所有这些代码。请尝试在Configure<OpenIdConnectOptions>(...)
中添加options.ResponseType = "code"
和options.SaveTokens = true;
以在授权cookie 中保存访问权限并可能刷新令牌,***.com/a/41953341/3936440 这样可以吗?以上是关于对如何在 Blazor App 中从 B2C 获取访问令牌感到困惑的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Azure AD B2C 保护 Blazor Wasm 应用访问的 Azure 函数?
使用 azure AD B2C 进行 blazor web api 身份验证
带有 Azure B2C 的 Blazor Web Assembly 应用程序总是在页面加载后立即尝试进行身份验证
在 Blazor WebAssembly 应用程序上加载请求 B2C 登录屏幕时出错