【问题标题】:Blazor webassembly - IdentityServer EventSink and HttpContextBlazor webassembly - IdentityServer EventSink 和 HttpContext
【发布时间】:2020-10-07 14:10:48
【问题描述】:

我正在使用带有 IdentityServer 的 ASP.NET Core 3.1 开发 Blazor webassembly 应用程序。 由于 IdentityServer 处理所有登录、注销、注册……事件,我试图捕捉这些事件以获取有关用户的一些信息。

为了清楚起见,我正在尝试记住登录日期,并捕捉新用户注册以自动赋予他们一些角色。

这是我在启动课程中使用的所有服务:

        services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddRoles<IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.Configure<IdentityOptions>(options =>
            options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);

        services.AddIdentityServer()
            .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
                options.IdentityResources["openid"].UserClaims.Add("name");
                options.ApiResources.Single().UserClaims.Add("name");
                options.IdentityResources["openid"].UserClaims.Add("role");
                options.ApiResources.Single().UserClaims.Add("role");
            });

        // Need to do this as it maps "role" to ClaimTypes.Role and causes issues
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

        services.AddAuthentication()
            .AddIdentityServerJwt();

我已经实现了 IEventSink 模式 (http://docs.identityserver.io/en/stable/topics/events.html):

public class IdentityServerEventSink : IEventSink
{
    private readonly UserManager<ApplicationUser> userManager;
    private readonly IHttpContextAccessor httpContextAccessor;

    public IdentityServerEventSink(UserManager<ApplicationUser> userManager, IHttpContextAccessor httpContextAccessor)
    {
        this.userManager = userManager;
        this.httpContextAccessor = httpContextAccessor;
    }

    public async Task PersistAsync(Event @event)
    {
        if (@event.Id.Equals(EventIds.ClientAuthenticationSuccess))
        {
            var identity = httpContextAccessor.HttpContext.User;
            var id = httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
            var user = await userManager.Users.FirstOrDefaultAsync(u => u.Id == id);
        }
    }
}

在 startup.cs 中:

services.AddHttpContextAccessor();
services.AddTransient<IEventSink, IdentityServerEventSink>();

但是当我进入 ClientAuthenticationSuccess 事件时,身份始终是匿名的。

我也在中间件中尝试过,但我遇到了同样的问题:

            app.Use(async (context, next) =>
        {
            await next.Invoke();
            //handle response
            //you may also need to check the request path to check whether it requests image
            if (context.User.Identity.IsAuthenticated)
            {
                var userName = context.User.Identity.Name;
                //retrieve uer by userName
                using (var dbContext = context.RequestServices.GetRequiredService<ApplicationDbContext>())
                {
                    var user = dbContext.Users.Where(u => u.UserName == userName).FirstOrDefault();
                    user.LastLogon = System.DateTime.Now;
                    dbContext.Update(user);
                    dbContext.SaveChanges();
                }
            }
        });

你有什么想法吗? 我听说 HttpContextAccessor 在 Blazor 中是个坏东西。

【问题讨论】:

  • 我不知道这是否正是您正在寻找的,但也许这会有所帮助:Blazor WebAssembly 3.2.0。 / .NET & EF 5 Preview - Multiple Roles and Additional User Claims 请参阅:github.com/JeepNL/Blazor-WASM-Identity-gRPC
  • 谢谢,这不是我需要的,但很有趣!!

标签: authentication identityserver4 blazor


【解决方案1】:

好的,更新后中间件委托工作!

app.Use(async (context, next) =>
{
    await next.Invoke();
    if (context.User.Identity.IsAuthenticated)
    {
        var userName = context.User.Identity.Name;
        using (var dbContext = context.RequestServices.GetRequiredService<ApplicationDbContext>())
        {
            var user = dbContext.Users.Where(u => u.UserName == userName).FirstOrDefault();
            if (user != null)
            {
                user.LastLogon = System.DateTime.Now;
                user.LastIpAddress = context.Connection?.RemoteIpAddress?.ToString();

                dbContext.Update(user);
                dbContext.SaveChanges();
            }
        }
    }
});

请注意配置方法中 app.use... 的顺序!您需要添加此AFTER app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization();

但很糟糕,来自 IdentityServer 的 EventSink 仍然无法正常工作,httpContextAccessor.HttpContext.User.Identity 始终是匿名的。

【讨论】:

  • 您是如何处理新用户注册的?我一直在研究在 Blazor Web Assembly 中处理此问题的最佳方法,但该部分似乎没有太多文档。文档似乎只涵盖身份验证和授权,而不是新用户的实际注册。听起来好像您正在从 Identity Server 中注册用户,但我很好奇您是如何从 blazor 客户端中处理这些的。你有我可以查看的示例代码或文档吗?
  • 这是个好问题!我还没有处理注册,但我需要控制它。也许您可以查看 github 上的 blazor-workshop 存储库。他们使用 IdentityServer。如果您对您的问题有任何回答,我想在这里
猜你喜欢
  • 2021-03-04
  • 2021-06-07
  • 2020-08-19
  • 2020-06-26
  • 2020-11-13
  • 1970-01-01
  • 2021-02-08
  • 2020-06-28
  • 2020-09-02
相关资源
最近更新 更多