重要提示:现在有比我的回答更好的来源。按照此答案最后部分提供的链接进行操作。
我使用 API / IdentityServer4 / Blazor(服务器端)进行了类似的设置。我给你看一些我使用的代码,也许你可以利用它。
使用 NuGet 包 Microsoft.AspNetCore.Authentication.OpenIdConnect,我在 Startup 类的 ConfigureServices 方法中得到了这段代码:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:5001";
options.ClientId = "myClient";
options.ClientSecret = "mySecret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("MyApi");
options.Scope.Add("offline_access");
options.ClaimActions.MapJsonKey("website", "website");
});
在配置方法app.UseAuthentication();
然后在 App.razor 中我使用了 CascadingAuthenticationState 组件:
<CascadingAuthenticationState>
<Router AppAssembly="typeof(Startup).Assembly" />
</CascadingAuthenticationState>
并在我的主页 Index.razor 中使用 NuGet 包 Microsoft.AspNetCore.Authorization:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
现在,当您打开主页时,它应该显示“未通过身份验证”,但仍然没有重定向到 IdentityServer4。为此,您还必须在启动时添加 MVC,正如我从 this stackoverflow question 学到的那样:
services.AddMvcCore(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
现在您应该会在启动应用程序后被重定向到 IdentityServer4 以登录。就我而言,我有一个 ApiClient,它描述了我的 API 的方法。我使用 DI 注入 ApiClient 并添加访问令牌:
services.AddHttpClient<IApiClient, ApiClient>(async (serviceProvider, client) =>
{
var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
var accessToken = await httpContextAccessor.HttpContext.GetTokenAsync("access_token");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("http://localhost:55578");
});
就像你说的,除了 stackoverflow 上的一些答案外,没有太多关于这个主题的文档。我花了很长时间来设置它,所以我希望我能在这篇文章中帮助其他人。
更新:注销过程
使用此设置注销需要绕行到 razor 页面,因为在加载 blazor 组件后无法访问 HttpContext。
在Pages文件夹中新建一个Razor页面,在新创建的Logout.cshtml.cs中添加如下代码:
public class LogoutModel : PageModel
{
public async void OnGetAsync()
{
await HttpContext.SignOutAsync("Cookies");
var prop = new AuthenticationProperties()
{
RedirectUri = "http://localhost:62909"
};
await HttpContext.SignOutAsync("oidc", prop);
}
}
在某处添加一个注销按钮,该按钮调用函数UriHelper.NavigateTo("/Logout"),依赖于@inject IUriHelper UriHelper。完成!
更新:登录解决方法
前面描述的登录过程在本地工作,但在发布到测试服务器后,我遇到了问题,IHttpContextAccessor 在AddHttpClient 方法中始终为空。所以我最终使用了与注销过程相同的解决方法。我让 IdentityServer 重定向到一个剃须刀页面(它总是有一个 HttpContext),将访问令牌保存在用户声明中并重定向到索引页面。在AddHttpClient 方法中,我只从用户声明中获取令牌并将其放入身份验证标头中。
更新:未解决的问题
我仍然很难让这个设置在我们的服务器上运行。我在 AspNetCore Github 上打开了 issue 和 requirement,但都在没有正确答案的情况下关闭了。目前,我发现一些博客可以很好地概述该主题的当前状态:
https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html
https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/