【问题标题】:Return "ui_locale" back to client将“ui_locale”返回给客户端
【发布时间】:2020-11-22 17:23:24
【问题描述】:

所以我知道如何让 IdentityServer4 应用程序使用具有挑战性的客户所拥有的文化。通过定义

options.Events = new OpenIdConnectEvents
{
   OnRedirectToIdentityProvider = context =>
   {
      context.ProtocolMessage.UiLocales = "pl-PL";
      return Task.CompletedTask;
   },                     
}

我可以让 IdentityServer4 在“pl-PL”中也显示登录页面。然而,诀窍是,我允许用户更改登录屏幕上的语言。如何通知客户在登录期间更改了文化信息? 目前我的客户端甚至没有显示任何页面,直接进入登录屏幕(因此从客户端应用程序浏览器立即重定向到 IdentityServer4 应用程序,用户可以在其中更改他/她的语言)。

【问题讨论】:

  • 登录后无法将信息发送回客户端。也许您可以共享一个 cookie 或添加使用的 ui_locale 作为声明。但也许你根本不应该使用这些信息,而只依赖于客户。
  • 我刚刚回答了一个类似的问题here
  • 我有使用声明的解决方案,但老实说,我希望 IdentityServer 中可能有一些内置的东西来实际处理这种情况。但如果没有,那么我想它是索赔解决方案。

标签: asp.net-core identityserver4


【解决方案1】:

这似乎不是 IdentityServer4 提供的功能(欢迎任何矛盾的 cmets)。所以我最终使用声明将文化信息传回给我的客户。 所以我创建了一个继承自IProfileService 的类,因此我可以将附加声明JwtClaimTypes.Locale 加载到idToken。然而,当它运行时,它似乎与运行它的用户处于不同的上下文中,因此CultureInfo.CurrentCulture 设置为与我期望的不同的语言环境(例如,UI 设置为pl-PL 但在配置文件中服务,它被设置为en-US)。所以我最终创建了一个InMemoryUserInfo 类,它基本上是一个包装好的ConcurrentDictionary,其中包含我的用户ID 和一个包含用户所选语言环境的对象。每当用户更改首选语言或从数据库提供用户语言时,我都会创建条目/更新该词典。无论如何,InMemoryUserInfo 然后被注入到我的配置文件服务中,在那里它被添加为另一个声明:

public class IdentityWithAdditionalClaimsProfileService : IProfileService
{
    private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
    private readonly UserManager<ApplicationUser> _userManager;
    
    /// <summary>
    /// This services is running in a different thread then UI, so
    /// when trying to obtain CultureInfo.CurrentUICulture, it not necessarily
    /// is going to be correct. So whenever culture is changed,
    /// it is stored in InMemoryUserInfo. Current user's culture will
    /// be included in a claim.
    /// </summary>
    private readonly InMemoryUserInfo _userInfo;

    public IdentityWithAdditionalClaimsProfileService(
        IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory,
        UserManager<ApplicationUser> userManager, 
        InMemoryUserInfo userInfo)
    {
        _claimsFactory = claimsFactory;
        _userManager = userManager;
        _userInfo = userInfo;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var sub = context.Subject.GetSubjectId();
        var user = await _userManager.FindByIdAsync(sub);
        var principal = await _claimsFactory.CreateAsync(user);

        var claims = principal.Claims.ToList();
        claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();            
       
        claims.Add(new Claim(JwtClaimTypes.Locale, _userInfo.Get(user.Id).Culture ?? throw new ArgumentNullException()));

        context.IssuedClaims = claims;
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        var sub = context.Subject.GetSubjectId();
        var user = await _userManager.FindByIdAsync(sub);
        context.IsActive = user != null;
    }
}

记得在DI注册IProfileService

services.AddTransient<IProfileService, IdentityWithAdditionalClaimsProfileService>();

之后,在我的客户启动中,我分析了OpenIdConnectEvents 中的声明,并将 cookie 设置为从 IdentityServer 接收的文化:

.AddOpenIdConnect("oidc", options =>
{
    options.Events = new OpenIdConnectEvents 
    {
        OnTicketReceived = context =>
        {
            //Goes through returned claims from authentication endpoint and looks for
            //localization info. If found and different, then new CultureInfo is set.
            string? culture = context.Principal?.FindFirstValue(JwtClaimTypes.Locale);
            if (culture != null && CultureInfo.CurrentUICulture.Name != culture)
            {
                context.HttpContext.Response.Cookies.Append(
                    CookieRequestCultureProvider.DefaultCookieName,
                    CookieRequestCultureProvider.MakeCookieValue(
                        new RequestCulture(culture, culture)),
                        new CookieOptions 
                        { Expires = DateTimeOffset.UtcNow.AddYears(1) }
                    );
            }
            return Task.CompletedTask;
        };
    }
});

【讨论】:

    猜你喜欢
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多