我正在努力在Identity Server 4服务中实现模拟功能。我知道有很多人反对以我想要的方式实现它,但是我确实需要完全重定向回SSO服务器才能生成新的声明列表。被冒充的用户将拥有与之关联的一组完全不同的规则作为声明,因此它必须来自IdSrvr。
我已阅读https://github.com/IdentityServer/IdentityServer4/issues/853和IdentityServer4 - How to Implement Impersonation
到目前为止,这是我一直在尝试的工作,即使在UserService上,我们也使用ACR值和Pre-Auth完美地在Identity Server 3中完成了此操作。
我从身份服务器的一个客户端调用此控制器方法:
public IActionResult Impersonate(string userIdToImpersonate, string redirectUri)
{
return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties(){RedirectUri = redirectUri, Items = { {"acr_values", $"userIdToImpersonate:{userIdToImpersonate}"}}});
}
这是我的OnRedirectToProvider:
OnRedirectToIdentityProvider = context =>
{
if (context.Properties.Items.ContainsKey("acr_values"))
{
context.ProtocolMessage.AcrValues = context.Properties.Items["acr_values"].ToString();
}
return Task.CompletedTask;
}
这是我开始迷路的地方,此刻,我已经继承自AuthorizeInteractionResponseGenerator
类,并使用对ProcessLoginAsync的重写实现了自己的类(这是我唯一发现的接近之处之前的pre-auth事件)
protected override async Task<InteractionResponse> ProcessLoginAsync(ValidatedAuthorizeRequest request)
{
if (!request.IsOpenIdRequest) return await base.ProcessLoginAsync(request);
var items = request.GetAcrValues();
if (items.Any(i => i.Contains("userIdToImpersonate")) && request.Subject.IsAuthenticated())
{
//handle impersonation
var userIdToImpersonate = items.FirstOrDefault(m => m.Contains("userIdToImpersonate")).Split(':').LastOrDefault();
request.Subject = await _signInManager.ImpersonateAsync(userIdToImpersonate);
//var userToImpersonate = await _signInManager.UserManager.FindByIdAsync(userIdToImpersonate);
//if (userToImpersonate == null) return await base.ProcessLoginAsync(request);
//var userBeingImpersonated = await _signInManager.UserManager.FindByIdAsync(userIdToImpersonate);
//var currentUserIdentity = await _signInManager.CreateUserPrincipalAsync(userBeingImpersonated);
//var currentClaims = currentUserIdentity.Claims.ToList();
//currentClaims.Add(new Claim(IdentityServiceClaimTypes.ImpersonatedById, request.Subject.IsBeingImpersonated() ? request.Subject.GetClaimValue(IdentityServiceClaimTypes.ImpersonatedById) : _signInManager.UserManager.GetUserId(request.Subject)));
//request.Subject = new ClaimsPrincipal(new ClaimsIdentity(currentClaims));
//return await base.ProcessLoginAsync(request);
return new InteractionResponse();
}
else
{
return await base.ProcessLoginAsync(request);
}
}
如您所见,我在这里尝试了几种不同的方法,当不使用OIDC作为身份验证方案,并且我的IdServer / Site是同一站点时,我可以使用模拟功能。 _signInManager.ImpersonateAsync(...)在哪里。这是该实现:
public async Task<ClaimsPrincipal> ImpersonateAsync(string userIdToImpersonate)
{
var userBeingImpersonated = await UserManager.FindByIdAsync(userIdToImpersonate);
if (userBeingImpersonated == null) return null;
var currentUserIdentity = await CreateUserPrincipalAsync(userBeingImpersonated);
var currentClaims = currentUserIdentity.Claims.ToList();
currentClaims.Add(new Claim(IdentityServiceClaimTypes.ImpersonatedById, Context.User.IsBeingImpersonated() ? Context.User.GetClaimValue(IdentityServiceClaimTypes.ImpersonatedById) : UserManager.GetUserId(Context.User)));
//sign out current user
await SignOutAsync();
//sign in new one
var newIdentity = new ClaimsPrincipal(new ClaimsIdentity(currentClaims));
await Context.SignInAsync(IdentityConstants.ApplicationScheme, newIdentity);
return Context.User;
}
为了简单地“替换”正在登录的人,或者至少是身份服务器正在考虑的登录人,我只是用模拟结果替换了Request.Subject。这实际上并没有改变我可以找到的任何东西,至少在我的客户端应用程序上没有。如果我使用“ https://localhost:44322/signin-oidc”的重定向URI(本地主机,因为我正在本地运行站点),则会收到“在登录-oidc重定向时关联失败”消息。如果有人实施了类似的操作或做了类似的事情,我将不胜感激帮助您完成此操作。
对于完全不同的实现,我们欢迎提出建议,这只是我对idsrvr3完美工作的最好选择。