IdentityServer4 自定义 AuthorizeInteractionResponseGenerator

20

很遗憾,关于在IdentityServer4中实现自定义AuthorizeInteractionResponseGenerator的文档非常缺乏。

我正在尝试实现自己的AuthorizeInteractionResponseGenerator,因为我需要进一步的用户交互步骤(在认证之后)。我的场景是单个身份(电子邮件)可以与多个租户相关联。因此,在登录后,我需要用户被呈现出与之关联的租户列表,以便他们可以选择一个。

我已经评估了源代码,并得出了以下自定义AuthorizeInteractionResponseGenerator

public class AccountChooserResponseGenerator : AuthorizeInteractionResponseGenerator
    {
        public AccountChooserResponseGenerator(ISystemClock clock, 
            ILogger<AuthorizeInteractionResponseGenerator> logger, 
            IConsentService consent, IProfileService profile) 
            : base(clock, logger, consent, profile)
        {
        }

        public override async Task<InteractionResponse> ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
        {
            var response = await base.ProcessInteractionAsync(request, consent);
            if (response.IsConsent || response.IsLogin || response.IsError)
                return response;

            return new InteractionResponse
            {
                RedirectUrl = "/Organization"
            };
        }
    }
它继承自IdentityServer4中基础的AuthorizeInteractionResponseGenerator,以便标准的登录和同意页面可以显示。这发生了,然后用户被正确地重定向到/Organization URL来选择组织(租户)。
但是接下来呢?由于缺乏文档和示例,我真的很难弄清以下两个问题:
1)选定租户后,我现在如何指示我的自定义AccountChooserResponseGenerator我的交互已经完成,并且现在可以将用户重定向回客户端?
编辑:
答案1:要表示交互已完成,您必须返回一个空的新InteractionResponse()。在我的情况下,检查TenantId声明是否存在就足够了,如下所示:
if (!request.Subject.HasClaim(c=> c.Type == "TenantId" && c.Value != "0"))
                return new InteractionResponse
                {
                    RedirectUrl = "/Organization"
                };

            return new InteractionResponse();

2) 我如何获得关于所选租户的信息,以便添加到IdentityServer4传回客户端的身份令牌中?

编辑:问题2的答案:在选取租户后执行的控制器动作方法中,我调用了:

 await HttpContext.SignInAsync(User.Claims.Single(r=> r.Type == "sub").Value,
                new System.Security.Claims.Claim("TenantId", tenant.Id.ToString()));

            return Redirect(ReturnUrl);

...这是一个由IdentityServer4提供的扩展,用于HttpContext。


2
我们使用部分登录实现了类似的功能。你可以从这个问题中获取一个例子:https://dev59.com/-Jzha4cB1Zd3GeqPGICa - mai
我们也做了类似的事情,一次是为了检查是否需要强制密码更改,另一次是为了检查租户是否唯一确定,或者是否需要要求用户进行选择。方法是在Login.cshtml.cs中创建一个名为public async Task<IActionResult> OnGetFinishLogin(string returnUrl = null)的方法,它将检查这些额外条件并适当地重定向,如果不需要处理,则重定向回客户端应用程序。 - Richard Barraclough
每当页面“认为”已完成登录时,它应该重定向到这个新操作。如果需要添加来自用户的额外信息作为声明,则可以将其添加为“UserClaim”(并在下次登录时用于预填充表单),但要小心不要累积重复项。 - Richard Barraclough
请注意,重定向到IdentityServer进行登录的客户端可以添加参数供IdentityServer使用。它们以以下方式出现: string tenantSubdomain = (await _interaction.GetAuthorizationContextAsync(returnUrl))?.Parameters["tenant"]. - Richard Barraclough
1个回答

1

要在Identity Server 4中实现自定义交互响应生成器并将所选租户的信息添加到身份令牌中,您可以从基类AuthorizeInteractionResponseGenerator继承并重写ProcessInteractionAsync方法。您还可以使用Identity Server 4提供的IProfileService接口,在发出令牌之前将租户信息作为声明添加到用户的身份中。

实现自定义交互响应生成器的步骤:

从基类AuthorizeInteractionResponseGenerator继承并重写ProcessInteractionAsync方法:

// Example implementation of ProcessInteractionAsync
public override async Task<InteractionResponse> ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
{
    // Your custom logic here

    // Indicate that the interaction is complete
    return new InteractionResponse();
}

将所选租户的信息添加到身份令牌中:

// Example implementation of IProfileService
public class CustomProfileService : IProfileService
{
    private readonly UserManager<ApplicationUser> _userManager;

    public CustomProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var user = await _userManager.GetUserAsync(context.Subject);
        if (user != null)
        {
            var tenantIdClaim = user.Claims.FirstOrDefault(c => c.Type == "TenantId");
            if (tenantIdClaim != null)
            {
                context.IssuedClaims.Add(new Claim("tenant_id", tenantIdClaim.Value));
            }
        }
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        return Task.CompletedTask;
    }
}

在你的Startup.cs文件中,注册CustomProfileService到Identity Server 4:

services.AddTransient<IProfileService, CustomProfileService>();

提示:

  1. 在重写 IdentityServer4 方法时,始终首先调用基类方法。
  2. 检查请求对象以获取有关当前流程的详细信息。
  3. 将 DEBUG 级别日志记录到标准输出以跟踪通过自定义逻辑的流程。
  4. 使用注入到生成器中的 IConsentServiceIProfileService 访问用户配置文件和同意数据。
  5. 检查 Identity Server 构建说明以编译源代码,这样可以更轻松地进行调试!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接