如何使用 IdentityServer4 身份验证以静默方式重新登录用户
How to re-login user silently using IdentityServer4 authentication
我们有基于第三方ABP框架及其多层架构的解决方案:
我们使用 Angular 作为网络界面,使用 IdentityServer4 进行用户身份验证。因此,我们是 运行 2 台主机 - HTTP API 主机和 IdentityServer 主机以及 Web 界面 - 它以标准方式工作:登录框,用户输入凭据 - 瞧。
不过,我们有一个自定义设置,允许在不同租户下使用相同的登录名。
租户列表显示为 UI 上的下拉列表,我们希望使用所选租户重新登录用户,而不是当前登录的用户。它需要看起来像一个简单的页面重新加载。问题是我不清楚如何实现它。我尝试使用来自应用层的以下调用,但它不起作用(错误是“没有为方案 'Identity.Application' 注册身份验证处理程序...”,但我不知道如何设置应用层的身份验证配置,以便能够与我们的 IdentityServer 一起工作):
[HttpGet]
public async Task<TenantDto> SwitchTenantForCurrentUser(Guid? tenantId)
{
var abxUser = await _abxUserRepository.FirstOrDefaultAsync(x => x.Login == CurrentUser.UserName && x.Tenant.AbpId == tenantId);
if (abxUser == null)
return null;
using var _ = _abpCurrentTenant.Change(tenantId);
var currentTenant = await _abxTenantRepository.FirstOrDefaultAsync(x => x.AbpId == _abpCurrentTenant.Id.Value);
var identityUser = await _identityUserRepository.FindByNormalizedUserNameAsync(abxUser.Login.ToUpper());
if (await _signInManager.CanSignInAsync(identityUser))
{
await _signInManager.SignOutAsync();
await _signInManager.SignInAsync(identityUser, true);
}
return ObjectMapper.Map<Tenant, TenantDto>(currentTenant); // Not decided yet what to return, it depends on proper implementation
}
来自 Http API 主机的关于身份验证的配置部分:
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = true;
options.ApiName = "CentralTools";
options.JwtBackChannelHandler = new HttpClientHandler
{
//TODO: use valid certificate in future and change the logic
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
});
context.Services.AddAbpIdentity().AddDefaultTokenProviders();
任务完成。
步骤:
BACK-END:在 IdentityServer 项目中实施并注册自定义授权类型验证器:
SwitchToTenantGrantValidator:IdentityServer4.Validation.IExtensionGrantValidator
简而言之,ValidateAsync 接受经过身份验证的用户的数据(他的访问令牌、租户 ID 等)并决定是否必须让用户进入。该方法将目标租户的数据写入上下文结果对象;
FRONT-END:使用给定的自定义授权类型调用 IdentityServer,提供 (1) 所需的数据。我们使用了 Angular,所以我不得不扩展 OAuthService 以支持自定义授权类型请求;
让一切井井有条(如果 (2) 成功)以在 UI 中显示正确的数据:清理旧状态等
我们有基于第三方ABP框架及其多层架构的解决方案:
我们使用 Angular 作为网络界面,使用 IdentityServer4 进行用户身份验证。因此,我们是 运行 2 台主机 - HTTP API 主机和 IdentityServer 主机以及 Web 界面 - 它以标准方式工作:登录框,用户输入凭据 - 瞧。
不过,我们有一个自定义设置,允许在不同租户下使用相同的登录名。 租户列表显示为 UI 上的下拉列表,我们希望使用所选租户重新登录用户,而不是当前登录的用户。它需要看起来像一个简单的页面重新加载。问题是我不清楚如何实现它。我尝试使用来自应用层的以下调用,但它不起作用(错误是“没有为方案 'Identity.Application' 注册身份验证处理程序...”,但我不知道如何设置应用层的身份验证配置,以便能够与我们的 IdentityServer 一起工作):
[HttpGet]
public async Task<TenantDto> SwitchTenantForCurrentUser(Guid? tenantId)
{
var abxUser = await _abxUserRepository.FirstOrDefaultAsync(x => x.Login == CurrentUser.UserName && x.Tenant.AbpId == tenantId);
if (abxUser == null)
return null;
using var _ = _abpCurrentTenant.Change(tenantId);
var currentTenant = await _abxTenantRepository.FirstOrDefaultAsync(x => x.AbpId == _abpCurrentTenant.Id.Value);
var identityUser = await _identityUserRepository.FindByNormalizedUserNameAsync(abxUser.Login.ToUpper());
if (await _signInManager.CanSignInAsync(identityUser))
{
await _signInManager.SignOutAsync();
await _signInManager.SignInAsync(identityUser, true);
}
return ObjectMapper.Map<Tenant, TenantDto>(currentTenant); // Not decided yet what to return, it depends on proper implementation
}
来自 Http API 主机的关于身份验证的配置部分:
private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
{
context.Services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = configuration["AuthServer:Authority"];
options.RequireHttpsMetadata = true;
options.ApiName = "CentralTools";
options.JwtBackChannelHandler = new HttpClientHandler
{
//TODO: use valid certificate in future and change the logic
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
};
});
context.Services.AddAbpIdentity().AddDefaultTokenProviders();
任务完成。 步骤:
BACK-END:在 IdentityServer 项目中实施并注册自定义授权类型验证器:
SwitchToTenantGrantValidator:IdentityServer4.Validation.IExtensionGrantValidator
简而言之,ValidateAsync 接受经过身份验证的用户的数据(他的访问令牌、租户 ID 等)并决定是否必须让用户进入。该方法将目标租户的数据写入上下文结果对象;
FRONT-END:使用给定的自定义授权类型调用 IdentityServer,提供 (1) 所需的数据。我们使用了 Angular,所以我不得不扩展 OAuthService 以支持自定义授权类型请求;
让一切井井有条(如果 (2) 成功)以在 UI 中显示正确的数据:清理旧状态等