用户模拟在.NET中的编程实现

用户模拟在.NET中的编程实现
 
发布日期:2007-07-18 | 更新日期:2009-03-14
作者:郑佐

摘要: 本文简单介绍在.NET中 进行Windows用户模拟设置和编程实现
 
本页内容
 
概述
在日常开发中经常会碰到这样的需求,在执行系统的某一部分功能代码时需要高于当前登录Windows用户的权限,一般常见的解决方案是使用身份模拟。本文通过简单的示例来讲解在.NET中实现模拟特定Windows用户执行特定操作的功能。
 
ASP.NET 身份模拟
在ASP.NET中,一种常见的方式是通过配置Web.Config来实现身份模拟。通过MSDN文档我们不难找到详细的描述。
在<system.web>元素下面放置以下元素节点:
<identity impersonate="true|false" userName="domain/username" password="password"/>
 
对于identity元素的一些属性代表的含义,可以直接参考 这里
简单的配置示例如下:
<identity impersonate="true" userName="DomainWeb/ASPNETOwner" password="Password"/>
 
上面的配置用户名和密码是通过明文保存的,因此存在安全隐患。值得关注的一种安全实现方式是把用户名和密码通过REG_BINARY注册表键类型格式保存到注册表的HKLM子项中。对于数据的加密通过Aspnet_setreg.exe工具来实现。
对于加密后的节点示例如下:
<identity impersonate="true" userName="registry:HKLM/Software/AspNetProcess,Name"password="registry:HKLM/Software/AspNetProcess,Pwd"/>
 
如果需要通过代码提供更多的灵活性,System.Security.Principal命名空间下的WindowsImpersonationContext类提供了对应的编程接口。
 
特定用户模拟
对于身份模拟来说,有时候需要特定的用户执行一些特定的代码,特别是在客户端程序应用中可能会存在这样的需求,那怎么实现呢?在Microsoft的客户支持和帮助的网站上提供了 实现方法 。为了让代码感觉上更友好,本文对其进行了简单的重构,整个功能通过ImpersonationHelper类来包装。
首先需要引用以下命名空间:
using  System;
using  System.Security.Principal;
using  System.Runtime.InteropServices;
 
另外,在实现过程中用到了以下平台调用:
[DllImport("advapi32.dll")]
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
 
类 中主要包含两个公共方法。Impersonate方法启用身份模拟,可以输入“域名/用户名称”和“密码”。如果模拟成功,返回true。否则模拟失败返 回false。EndImpersonate方法同Impersonate方法成对出现,通过调用该方法结束指定身份的模拟。
public  bool Impersonate(String userName, String password);
public  void EndImpersonate();
 
以下是ImpersonationHelper类的定义。
public  sealed class ImpersonationHelper
{
    private const int LOGON32_LOGON_INTERACTIVE = 2;
    private const int LOGON32_PROVIDER_DEFAULT = 0;
 
    private WindowsImpersonationContext impersonationContext;
 
    [DllImport("advapi32.dll")]
    private static extern int LogonUserA(String lpszUserName,String lpszDomain,String lpszPassword,int dwLogonType,int dwLogonProvider,ref IntPtr phToken);
       
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int DuplicateToken(IntPtr hToken,int impersonationLevel,ref IntPtr hNewToken);
 
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool RevertToSelf();
 
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    private static extern bool CloseHandle(IntPtr handle);
 
    public ImpersonationHelper()
    {           
}
 
    private bool Impersonate(String userName, String domain, String password)
    {
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;
        if (RevertToSelf())
        {
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    WindowsIdentity tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    impersonationContext = tempWindowsIdentity.Impersonate();                       
                    if (impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        return true;
                    }
                }
            }
        }
        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
        return false;
    }
       
    public bool Impersonate(String userName, String password)
    {
        if (userName.IndexOf('//') != -1)
        {
            string[] s = userName.Split('//');
            return Impersonate(s[1], s[0], password);
        }
        return Impersonate(userName, null, password);
    }
   
    public void EndImpersonate()
    {
        impersonationContext.Undo();
    }
}
 
应用示例
下面是一个简单通过ImpersonationHelper类实现身份模拟的示例,具体逻辑在CallMethod中。
class  ClientCaller
{
    public void CallMethod()
    {
        ImpersonationHelper helper = new ImpersonationHelper();
        if (helper.Impersonate("domain//username", "password"))
        {
            // 在这里插入需要执行模拟用户权限的代码。
            // 代码...
            helper.EndImpersonate();// 结束身份模拟。
        }
        else
        {
            // 如果模拟失败在这里处理。
        }
}
}
 
测试过程中可以采用以下设置方案。
在系统中建立不同的目录(假设为NTFS文件系统),在文件夹的属性对话框中选择安全选项卡,设置特定的帐户权限,在代码中模拟不同的用户访问这些文件夹来验证模拟的正确性。
 
结束语
查看ImpersonationHelper的实现,不难发现在复杂的应用中需要注意的几个问题:
(1) ImpersonationHelper 不是线程安全的;
(2)ImpersonationHelper 的两个方法 Impersonate 和EndImpersonate必须成对出现,而且不能嵌套调用。
另外,对于ImpersonationHelper类的两个方法改为静态,或者实现一个传递delegate的 Impersonate 重载方法,使用起来是不是会更有趣一些,当然更可以完全改造ImpersonationHelper类。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值