Levy.Net

它山之石,可以为错; 它山之石,可以攻玉
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

在Asp.Net中委托异步调用(或多线程)中的身份模拟

Posted on 2008-04-09 17:49  LevyLiu  阅读(1113)  评论(0)    收藏  举报

在Asp.net开发的应用程序中,会有以windows集成认证的用户登录方式。会有这样的应用场景:
  用户在本地上传一个Excel文件,其中包含了一些在本地编辑好的业务数据,需要上传到服务器更新到数据库中。作为服务端代码需要作很多的检查,以确保用户编辑的数据是有效的,这就需要较长时间的操作,不可能让用户在客户端(如IE)前一直等待返回。这就需要用委托的异步调用或多线程来处理上传文件后的操作。
因为新开辟的线程不同于主线程,它是以运行Asp.net的进程的user来启动的。(XP下的asp.net的进程是aspnet_wp.exe,对应的user是ASPNET,而在Windows server2003是w3wp.exe,对应的user是NETWORK SERVICE)
  在新线程中免不了要访问数据库等需要身份验证的操作,以Asp.net的进程的user来验证显然是不正确的,这就需要把主线程的身份传到新线程中,在新线程中进行模拟。好在.Net Framework为我们提供了很简便的方法,下面看一下实例:

 

public delegate void AsyncConfirmMultipleCall(string confirmFile);

public class Test
{
    
private System.Security.Principal.WindowsIdentity curIndentity;

    
public void LongTimeHandle(string confirmFile)
    
{
        WindowsImpersonationContext impersonatedUser 
= WindowsIdentity.Impersonate(curIndentity.Token);            
        
try
        
{
            
//Your code

            
string userName = Environment.UserName;
        }

        
catch (Exception ex)
        
{
        }

        
finally
        
{
            impersonatedUser.Undo();
        }

    }


    
public void LongTimeHandleAsync(string confirmFile)
    
{
        curIndentity 
= System.Security.Principal.WindowsIdentity.GetCurrent();

        AsyncConfirmMultipleCall handle 
= new AsyncConfirmMultipleCall(LongTimeHandle);
        handle.BeginInvoke(confirmFile, 
new AsyncCallback(CallbackMethod), handle);
    }


    
private void CallbackMethod(IAsyncResult ar)
    
{
        AsyncConfirmMultipleCall handle 
= ar.AsyncState as AsyncConfirmMultipleCall;
        handle.EndInvoke(ar);
    }

}

  这里提供了异步方法LongTimeHandleAsync
  在开始异步调用之前,先取得当前线程的user信息curIndentity.然后最关键的代码就是:
  WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(curIndentity.Token);
  在这里,就开始了身份的模拟。这是WindowsIdentity的静态方法,它也提供有实例方法。将之前user的Token传入进行模拟。特别要注意,在代码结束前一定要恢复用户的标识,所以,比较好的做法是在try/catch/finally的finally块中调用impersonatedUser.Undo()
  如果不进行身份模拟,string userName的值会是"ASPNET"(或"NETWORK SERVICE")而不是用户的Window user.