如何解决使用 Google 身份验证通过 Blazor WASM 静态 Web 应用程序保护 Azure 函数 API
我正在开发 Blazor WASM 应用程序,并设法使用 Google 身份验证(我们不想使用任何其他类型的身份验证)使其作为静态 Web 应用程序运行。我也在为我的 Azure 函数 API 使用自带函数。
它的工作方式是,一旦用户使用他们的 Google 帐户登录,我的应用就会获取他们的电子邮件,并将其与数据库中的“注册用户”列表进行比较,以确定用户的角色。然后我使用自定义帐户工厂来添加这些角色,这允许我根据当前登录用户的角色显示/隐藏我的 WASM 应用程序的各种元素。所有这些都适用于开发人员和我将静态 Web 应用程序发布到 Azure 后。
挑战在于我似乎无法确保 API 的安全,它目前完全开放,但我希望它仅对某些角色可用。我在互联网上做了大量研究,但一切似乎都过时了(我使用的是 NET 5.0,因为静态 Web 应用程序似乎还不支持 NET 6.0 预览版)。到目前为止,我有以下选项:
-
改用 EasyAuth,并使用 staticwebapp.config.json 中的路由保护 API。这完全解决了我的 API 授权问题,但 .auth/me 端点只给我用户的电子邮件地址(不是我目前使用 OIDC 授权流程获得的所有其他 Google 个人资料信息)。我还需要从数据库中添加相关角色,以便在调用 API 时发出它们。
-
通过 AddHttpMessageHandler() 将 Google 访问令牌传递给 HTTP 请求,这似乎有效,因为我在授权标头中看到了“Bearer XXX”,但我不确定如何获取我的 Azure Function API消费它。另外 - 这不考虑角色要求,不知何故我还需要从令牌中获取用户信息。
以上两个哪个更有意义,还是我错过了更明显的第三个选项?
请注意,用户和角色需要通过应用添加,而不是通过 Azure 门户,因此我使用数据库来存储电子邮件地址和角色。
我的WASM代码如下:
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
var baseAddress = builder.Configuration["BaseAddress"] ?? builder.HostEnvironment.BaseAddress;
builder.Services.AddHttpClient("MyApp.Api",client => client.BaseAddress = new Uri(baseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>(); ;
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("MyApp.Api"));
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Local",options.ProviderOptions);
options.ProviderOptions.DefaultScopes.Add("email");
})
.AddAccountClaimsPrincipalFactory<RemoteAuthenticationState,RemoteUserAccount,CustomAccountFactory>();
;
await builder.Build().RunAsync();
}
}
CustomAccountFactory.cs
public class CustomAccountFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
IHttpClientFactory _httpFactory;
public CustomAccountFactory(NavigationManager navigationManager,IAccessTokenProviderAccessor accessor,IHttpClientFactory httpClient) : base(accessor)
{
_httpFactory = httpClient;
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(RemoteUserAccount account,RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account,options);
if (initialUser.Identity.IsAuthenticated)
{
var email = initialUser.FindFirst("email")?.Value;
try
{
var _httpClient = _httpFactory.CreateClient("MyApp.Api");
var userRole = await _httpClient.GetFromJsonAsync<string>($"api/UserRole?email={email}");
((ClaimsIdentity)initialUser.Identity).AddClaim(new Claim(ClaimTypes.Role,userRole));
}
catch (Exception ex)
{
throw new Exception($"Could not get user roles from the API. Please check it is running. {ex.Message} {ex.InnerException?.Message}");
}
}
return initialUser;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。