使用Web Api临时更改身份2

时间:2015-03-05 07:02:11

标签: c# asp.net-identity owin claims-based-identity

我有一个WebApi控制器,最初作为特定的WebApi用户进行身份验证。对web api的后续访问将向用户传递应该执行操作,而不必实际验证该用户。

我有一些服务/经理作为MVC项目的一部分执行作为适当用户的功能。我现在想在WebApi项目中使用这些服务和经理,但我不想让用户通过。

我希望在用户传入Web Api呼叫后,我可以暂时更改Web Api呼叫的身份,但我想确保在呼叫完成后,返回的cookie是用于验证WebApi用户,而不是表示为呼叫一部分的最终用户。

我的问题是,如何暂时将身份更改为呼叫中经过验证的用户,然后更改回网络API身份?

1 个答案:

答案 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没有足够的经验,或者耐心等待打扰。