Веб-сборка Blazor - IdentityServer EventSink и HttpContext - PullRequest
4 голосов
/ 17 июня 2020

Я работаю над приложением веб-сборки Blazor в ASP. NET Core 3.1 с IdentityServer. Поскольку IdentityServer обрабатывает все события входа, выхода, регистрации и т. Д., Я пытаюсь перехватить эти события, чтобы получить некоторую информацию о пользователях.

Для ясности, я пытаюсь запомнить логин Date, а также для регистрации новых пользователей, чтобы автоматически дать им некоторую роль.

Здесь все службы, которые я использую в своем классе запуска:

        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.

1 Ответ

0 голосов
/ 30 июня 2020

Итак, после обновления делегат промежуточного ПО работает!

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 ... в методе Configure! Вам нужно добавить это ПОСЛЕ app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization();

Но, к сожалению, EventSink от IdentityServer по-прежнему не работает, httpContextAccessor.HttpContext.User.Identity всегда анонимный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...