Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用WebApi 2临时更改标识_C#_Asp.net Identity_Owin_Claims Based Identity - Fatal编程技术网

C# 使用WebApi 2临时更改标识

C# 使用WebApi 2临时更改标识,c#,asp.net-identity,owin,claims-based-identity,C#,Asp.net Identity,Owin,Claims Based Identity,我有一个WebApi控制器,它最初作为特定的WebApi用户进行身份验证。对web api的后续访问将传递给一个用户,该用户应该作为该用户执行操作,而不必实际作为该用户进行身份验证 我有一些服务/经理,作为MVC项目的一部分,作为适当的用户执行功能。我现在想在WebApi项目中使用这些服务和管理器,但我不想让用户知道 我希望在验证传入Web Api调用的用户后,可以临时更改Web Api调用的标识,但我希望确保调用完成后,返回的cookie用于验证WebApi用户,而不是表示为调用一部分的最终用

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

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

我希望在验证传入Web Api调用的用户后,可以临时更改Web Api调用的标识,但我希望确保调用完成后,返回的cookie用于验证WebApi用户,而不是表示为调用一部分的最终用户


我的问题是,我可以做些什么来临时将身份更改为调用中的已验证用户,然后再更改回web api身份?

松散地使用文章中链接中的代码,我创建了一个IDisposable对象来临时更改身份

用途是:

try
{
    using(new Impersonate(userManager, userName))
    {
       /* do your stuff as userName */
    }
}
catch (ImpersonateException) {}
模拟类如下所示:

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;
    }
}
公共类模拟:IDisposable
{
私有用户管理器用户管理器;
公共模拟(UserManager UserManager,字符串用户名)
{
this.userManager=userManager;
如果(验证用户(用户名))
{
this.ImpersonateUser(用户名);
}
其他的
{
抛出新的ImpersonateException(“当前用户没有模拟用户的权限”);
}
}
私有bool ValidateUser(字符串用户名)
{
/*验证当前用户是否可以模拟用户名*/
}
公共空间处置()
{
此为.revertimersonation();
}
私有void模拟用户(字符串用户名)
{
var context=HttpContext.Current;
var originalUsername=context.User.Identity.Name;
var impersonatedUser=this.userManager.FindByName(用户名);
var impersonatedIdentity=impersonatedUser.GenerateUserIdentity(this.userManager,“模拟”);
impersonatedIdentity.AddClaim(新声明(“UserImpersonation”、“true”);
impersonatedIdentity.AddClaim(新声明(“OriginalUsername”,OriginalUsername));
var impersonatedPrincipal=new-ClaimsPrincipal(impersonatedIdentity);
context.User=impersonatedPrincipal;
Thread.CurrentPrincipal=impersonatedPrincipal;
}
私有无效还原模拟()
{
var context=HttpContext.Current;
如果(!ClaimsPrincipal.Current.IsImpersonating())
{
抛出新的模拟异常(“无法删除模拟,因为没有模拟”);
}
var originalUsername=ClaimsPrincipal.Current.GetOriginalUsername();
var originalUser=this.userManager.FindByName(originalUsername);
var originalIdentity=originalUser.GenerateUserIdentity(this.userManager);
var originalPrincipal=新的索赔(原始身份);
context.User=originalPrincipal;
Thread.CurrentPrincipal=originalPrincipal;
}
}
这与链接代码的不同之处在于,它仅临时设置标识,因此不需要进行登录/注销

此外,由于大部分工作是在构造函数中完成的,因此我必须删除链接代码使用的异步方面。也许有办法解决这个问题,但我对异步没有足够的经验,也没有足够的耐心来解决这个问题。

找到了一篇很好的文章[,和相关的SO Q[这让我有了一点想法。在这一点上,我认为一个可以进行验证、模拟和恢复的一次性对象可能是合适的。