带有 IdentityServer4 的 Blazor(服务器端)

Blazor(server-side) with IdentityServer4

我正在尝试让 IdentityServer4(使用本地 API)与 Blazor(服务器端)前端一起工作。

我已经能够创建 IdentityServer 后端。登录功能有效,它根据后端的 ASP.NET 身份设置进行身份验证。一旦通过身份验证,我就可以(使用 Postman)获取 Bearer 令牌并调用 API 以获得成功的结果。

我想知道是否有人知道如何:

  1. 当转到一个页面时自动重定向 Blazor(服务器端) 需要授权
  2. 一旦用户成功登录 IdentityServer,如何将该信息传递到 context.User Blazor 应用程序。如果这可能的话,我可能有 这里的术语有误。

我希望最终的决定不是仅仅使用 odic-client.js 来进行这些调用。即使结果是这样,是否可以从 IdentityServer 取回该信息并将其推入 context.User?

更新:

我已经能够将 Blazor 网站绑定到 IdentityServer(不是 #1 中想要的自动定向)来测试功能。

returnUrl 正在从 IdentityServer 重定向(成功登录后)。这看起来也像是将 AspNetCore.Identity.Application cookie 写入 Blazor 网站 cookie。

有没有办法从 cookie 中获取该信息(如果它包含用户和不记名令牌)?

更新:

我发现 Blazor 代码可能正在尝试读取 cookie,但我不知道如何验证。我在输出中得到这个:

Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.Application signed in.
Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (1ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [u].[Id], [u].[AccessFailedCount], [u].[ConcurrencyStamp], [u].[Email], [u].[EmailConfirmed], [u].[LockoutEnabled], [u].[LockoutEnd], [u].[NormalizedEmail], [u].[NormalizedUserName], [u].[PasswordHash], [u].[PhoneNumber], [u].[PhoneNumberConfirmed], [u].[SecurityStamp], [u].[TwoFactorEnabled], [u].[UserName]
FROM [AspNetUsers] AS [u]
WHERE [u].[NormalizedUserName] = @__normalizedUserName_0
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method IdentityServer4.Quickstart.UI.AccountController.Login (BQM.API), returned result Microsoft.AspNetCore.Mvc.RedirectResult in 651.558ms.
Microsoft.AspNetCore.Mvc.Infrastructure.RedirectResultExecutor:Information: Executing RedirectResult, redirecting to https://localhost:44370/.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action IdentityServer4.Quickstart.UI.AccountController.Login (BQM.API) in 777.6252ms
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executed endpoint 'IdentityServer4.Quickstart.UI.AccountController.Login (BQM.API)'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 890.8492ms 302 
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/1.1 GET https://localhost:44370/  
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint '/_Host'
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker: Information: Route matched with {page = "/_Host", area = ""}. Executing page /_Host
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker: Information: Executing an implicit handler method - ModelState is Valid
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker: Information: Executed an implicit handler method, returned result Microsoft.AspNetCore.Mvc.RazorPages.PageResult.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed.
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker: Information: Executed page /_Host in 16.8805ms

希望对您有所帮助。

我需要令牌,因为我想调用受此令牌保护的 API。您必须将内容添加到 Startup.cs 并稍后检索它,您可以查看 Startup.cs

下面的 class

这是 Startup.cs 中需要的(重要部分是 HttpContextAccessor)。

你需要以下使用 i Startup.cs

using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;

然后(仍在 Startup.cs):

public void ConfigureServices(IServiceCollection services)
    {

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = 
CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = 
OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.Authority = "https://localhost:5001/";
            options.ClientId = "AuthCodeClient";
            options.ClientSecret = "verrystrongpwd";
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.SaveTokens = true;
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("user.management.api");
            options.Scope.Add("identity-provider.Api");
            options.CallbackPath = "/signin-oidc";
        });

        services.AddControllersWithViews(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        });

        services.AddRazorPages();
        services.AddServerSideBlazor();

        // HttpContextAccessor
        services.AddHttpContextAccessor();
        services.AddScoped<HttpContextAccessor>();

........ maybe more code....

她是我从 HttpContext 检索信息的 class,如 access_token

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Management.Ui.Services
{
  public class TokenContainer
  {
    private readonly IHttpContextAccessor _httpContextAccessor;

    public TokenContainer(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    protected async Task AddRequestHeaders(HttpClient httpClient)
    {
        var accessToken = await _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
        httpClient.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    }
  }
}