如何创建 API/IdentityServer/Blazor(服务器端)应用程序?
How do you create a API/IdentityServer/Blazor(server-side) application?
我试图自己构建此应用程序,但一路上遇到了几个绊脚石。我在想,最好退后一步,更全面地审视我正在尝试创造的东西。似乎没有关于如何制作我正在寻找的东西的任何文档。 (除非有人能指出我可能错过的正确位置)
最终我想要的是让 Blazor(服务器端)应用程序进行 API 调用以使用应用程序中的数据,然后让 IdentityServer4 封装身份验证。我需要 Azure 以及 ASP.net Identity 作为可能的身份验证方法。
我已经尝试并能够创建一个也有本地 API 的 IdentityServer4。我可以从 Postman 调用它来获取令牌等。但是,当谈到将 Blazor(服务器端)应用程序绑定到 IdentityServer4 时,我感到很困惑。
这个问题我已经试过具体询问了,但是一点结果都没有。我希望这种更大的观察可能会有所帮助。
odic-client.js 似乎是从 IdentityServer4 回调中获取数据的方法,但是,这似乎与 Blazor(服务器端)中的 .NET 授权没有很好的结合。我如何让它们协同工作。
重要提示:现在有比我的回答更好的资源。请点击此答案最后部分提供的链接。
我有一个与 API / IdentityServer4 / Blazor(server-side) 类似的设置。我会展示一些我使用的代码,也许你可以使用它。
使用 NuGet 包 Microsoft.AspNetCore.Authentication.OpenIdConnect,我在 Startup class:
的 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");
});
并在 Configure 方法中 app.UseAuthentication();
然后在 App.razor 我使用了 CascadingAuthenticationState 组件:
<CascadingAuthenticationState>
<Router AppAssembly="typeof(Startup).Assembly" />
</CascadingAuthenticationState>
并在我的主页中使用 NuGet 包 Microsoft.AspNetCore.Authorization Index.razor:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
现在当您打开主页时它应该说 "Not authenticated" 但仍然没有重定向到 IdentityServer4。为此,您还必须在启动中添加 MVC,正如我从 this Whosebug 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");
});
正如您所说,除了 Whosebug 上的一些答案外,关于这个主题的文档不多。我花了很长时间来设置它,所以我希望我能帮助其他人 post。
更新:注销过程
使用此设置注销需要绕道到 razor 页面,因为加载 blazor 组件后无法访问 HttpContext。
在Pages文件夹中新建一个Razor Page,在新建的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
的某处添加注销按钮。完成!
更新:登录解决方法
之前描述的登录过程在本地有效,但在发布到测试服务器后,我遇到了问题,即 AddHttpClient
方法中的 IHttpContextAccessor
始终为 null。所以我最终使用了与注销过程相同的解决方法。我让 IdentityServer 重定向到一个剃刀页面(它总是有一个 HttpContext),将访问令牌保存在用户声明中并重定向到索引页面。在 AddHttpClient
方法中,我只从用户声明中获取令牌并将其放入身份验证 header.
更新:未决问题
我仍然很难让这个设置在我们的服务器上运行。我在 AspNetCore Github 上打开了这个 issue and requirement,但都在没有正确答案的情况下关闭了。目前,我发现一些博客很好地概述了该主题的当前状态:
https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html
https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/
我试图自己构建此应用程序,但一路上遇到了几个绊脚石。我在想,最好退后一步,更全面地审视我正在尝试创造的东西。似乎没有关于如何制作我正在寻找的东西的任何文档。 (除非有人能指出我可能错过的正确位置)
最终我想要的是让 Blazor(服务器端)应用程序进行 API 调用以使用应用程序中的数据,然后让 IdentityServer4 封装身份验证。我需要 Azure 以及 ASP.net Identity 作为可能的身份验证方法。
我已经尝试并能够创建一个也有本地 API 的 IdentityServer4。我可以从 Postman 调用它来获取令牌等。但是,当谈到将 Blazor(服务器端)应用程序绑定到 IdentityServer4 时,我感到很困惑。
这个问题我已经试过具体询问了,但是一点结果都没有。我希望这种更大的观察可能会有所帮助。
odic-client.js 似乎是从 IdentityServer4 回调中获取数据的方法,但是,这似乎与 Blazor(服务器端)中的 .NET 授权没有很好的结合。我如何让它们协同工作。
重要提示:现在有比我的回答更好的资源。请点击此答案最后部分提供的链接。
我有一个与 API / IdentityServer4 / Blazor(server-side) 类似的设置。我会展示一些我使用的代码,也许你可以使用它。
使用 NuGet 包 Microsoft.AspNetCore.Authentication.OpenIdConnect,我在 Startup class:
的 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");
});
并在 Configure 方法中 app.UseAuthentication();
然后在 App.razor 我使用了 CascadingAuthenticationState 组件:
<CascadingAuthenticationState>
<Router AppAssembly="typeof(Startup).Assembly" />
</CascadingAuthenticationState>
并在我的主页中使用 NuGet 包 Microsoft.AspNetCore.Authorization Index.razor:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
现在当您打开主页时它应该说 "Not authenticated" 但仍然没有重定向到 IdentityServer4。为此,您还必须在启动中添加 MVC,正如我从 this Whosebug 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");
});
正如您所说,除了 Whosebug 上的一些答案外,关于这个主题的文档不多。我花了很长时间来设置它,所以我希望我能帮助其他人 post。
更新:注销过程
使用此设置注销需要绕道到 razor 页面,因为加载 blazor 组件后无法访问 HttpContext。
在Pages文件夹中新建一个Razor Page,在新建的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
的某处添加注销按钮。完成!
更新:登录解决方法
之前描述的登录过程在本地有效,但在发布到测试服务器后,我遇到了问题,即 AddHttpClient
方法中的 IHttpContextAccessor
始终为 null。所以我最终使用了与注销过程相同的解决方法。我让 IdentityServer 重定向到一个剃刀页面(它总是有一个 HttpContext),将访问令牌保存在用户声明中并重定向到索引页面。在 AddHttpClient
方法中,我只从用户声明中获取令牌并将其放入身份验证 header.
更新:未决问题
我仍然很难让这个设置在我们的服务器上运行。我在 AspNetCore Github 上打开了这个 issue and requirement,但都在没有正确答案的情况下关闭了。目前,我发现一些博客很好地概述了该主题的当前状态: https://mcguirev10.com/2019/12/15/blazor-authentication-with-openid-connect.html https://wellsb.com/csharp/aspnet/blazor-consume-identityserver4-protected-api/