我有一个WebApi控制器,最初作为特定的WebApi用户进行身份验证。对web api的后续访问将向用户传递应该执行操作,而不必实际验证该用户。
我有一些服务/经理作为MVC项目的一部分执行作为适当用户的功能。我现在想在WebApi项目中使用这些服务和经理,但我不想让用户通过。
我希望在用户传入Web Api呼叫后,我可以暂时更改Web Api呼叫的身份,但我想确保在呼叫完成后,返回的cookie是用于验证WebApi用户,而不是表示为呼叫一部分的最终用户。
我的问题是,如何暂时将身份更改为呼叫中经过验证的用户,然后更改回网络API身份?
答案 0 :(得分:0)
使用帖子中链接的代码,我创建了一个暂时更改身份的IDisposable对象。
用法是:
try
{
using(new Impersonate(userManager, userName))
{
/* do your stuff as userName */
}
}
catch (ImpersonateException) {}
Impersonate类如下:
public class Impersonate : IDisposable
{
private UserManager<ApplicationUser> userManager;
public Impersonate(UserManager<ApplicationUser> userManager, string userName)
{
this.userManager = userManager;
if (ValidateUser(userName))
{
this.ImpersonateUser(userName);
}
else
{
throw new ImpersonateException("Current user does not have permissions to impersonate user");
}
}
private bool ValidateUser(string userName)
{
/* validate that the current user can impersonate userName */
}
public void Dispose()
{
this.RevertImpersonation();
}
private void ImpersonateUser(string userName)
{
var context = HttpContext.Current;
var originalUsername = context.User.Identity.Name;
var impersonatedUser = this.userManager.FindByName(userName);
var impersonatedIdentity = impersonatedUser.GenerateUserIdentity(this.userManager, "Impersonation");
impersonatedIdentity.AddClaim(new Claim("UserImpersonation", "true"));
impersonatedIdentity.AddClaim(new Claim("OriginalUsername", originalUsername));
var impersonatedPrincipal = new ClaimsPrincipal(impersonatedIdentity);
context.User = impersonatedPrincipal;
Thread.CurrentPrincipal = impersonatedPrincipal;
}
private void RevertImpersonation()
{
var context = HttpContext.Current;
if (!ClaimsPrincipal.Current.IsImpersonating())
{
throw new ImpersonationException("Unable to remove impersonation because there is no impersonation");
}
var originalUsername = ClaimsPrincipal.Current.GetOriginalUsername();
var originalUser = this.userManager.FindByName(originalUsername);
var originalIdentity = originalUser.GenerateUserIdentity(this.userManager);
var originalPrincipal = new ClaimsPrincipal(originalIdentity);
context.User = originalPrincipal;
Thread.CurrentPrincipal = originalPrincipal;
}
}
这与链接代码的不同之处在于它只是暂时设置标识,因此不需要使用SignIn / SignOut。
此外,由于大部分工作是在构造函数中完成的,因此我不得不删除链接代码使用的Async方面。可能有办法绕过它,但我对Async没有足够的经验,或者耐心等待打扰。