identity 收藏
============================================================
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using System.Windows.Forms;
[assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode = true)]
[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "FullTrust")]
public class ImpersonationDemo
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource,
int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
// Test harness.
// If you incorporate this code into a DLL, be sure to demand FullTrust.
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public static void Main(string[] args)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr(0);
try
{
string userName, domainName;
// Get the user token for the specified user, domain, and password using the
// unmanaged LogonUser method.
// The local machine name can be used for the domain name to impersonate a user on this machine.
Console.Write("Enter the name of the domain on which to log on: ");
domainName = Console.ReadLine();
Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
userName = Console.ReadLine();
Console.Write("Enter the password for {0}: ", userName);
const int LOGON32_PROVIDER_DEFAULT = 0;
//This parameter causes LogonUser to create a primary token.
const int LOGON32_LOGON_INTERACTIVE = 2;
tokenHandle = IntPtr.Zero;
// Call LogonUser to obtain a handle to an access token.
bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
Console.WriteLine("LogonUser called.");
if (false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
throw new System.ComponentModel.Win32Exception(ret);
}
Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
Console.WriteLine("Value of Windows NT token: " + tokenHandle);
// Check the identity.
Console.WriteLine("Before impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Use the token handle returned by LogonUser.
WindowsIdentity newId = new WindowsIdentity(tokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
// Check the identity.
Console.WriteLine("After impersonation: "
+ WindowsIdentity.GetCurrent().Name);
// Stop impersonating the user.
impersonatedUser.Undo();
// Check the identity.
Console.WriteLine("After Undo: " + WindowsIdentity.GetCurrent().Name);
// Free the tokens.
if (tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
}
catch (Exception ex)
{
Console.WriteLine("Exception occurred. " + ex.Message);
}
}
}
========================================
15.2 用户账户模拟
15.2.1 一个模拟请求用户的例子
和以前的ASP不同,ASP.NET默认不模拟发出请求的用户。因此,可能发生以下情况。
· 由于ASP.NET系统账户默认权限不够高,不能执行一些对权限要求比较高的操作(比如磁盘访问、活动目录操作等)。
· ASP.NET系统账户权限设置得过高,匿名用户都能执行“危险”操作。
我们可以通过开启模拟让ASP.NET以请求的账号来执行。一起来做一个试验。
1.新建一个ASPX页面,在Page_Load中我们输出请求标识和身份验证类型。(需要using System.Security.Principal;)。
protected void Page_Load(object sender, EventArgs e)
{
WindowsIdentity userIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal userPrincipal = new WindowsPrincipal(userIdentity);
Response.Write(string.Format("当前用户标识:{0}<br/>" , userPrincipal.
Identity.Name));
Response.Write(string.Format("身份验证类型:{0}<br/>" , userPrincipal.
Identity.AuthenticationType));
}
在页面上放置一个按钮控件和一个GridView控件。
<asp:Button ID="btn_GetFileList" runat="server" OnClick="btn_GetFileList_Click"
Text="获取文件列表" />
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
按钮控件的单击事件处理方法如下(需要using System.IO;):
protected void btn_GetFileList_Click(object sender, EventArgs e)
{
DirectoryInfo di = new DirectoryInfo(@"d:/test");
GridView1.DataSource = di.GetFiles();
GridView1.DataBind();
}
可以看到,单击按钮后我们读取d盘的test目录的文件列表并绑定到GridView上进行呈现。
新建一个Web.config文件,配置如下:
<?xml version="1.0"?>
<configuration>
<system.web>
<identity impersonate="true"/> <!--开启模拟-->
</system.web>
</configuration>
2.配置IIS,把程序所在的目录配置成一个虚拟目录,并且设置这个虚拟目录为关闭匿名访问,开启Windows集成验证,如图15-2所示。
注意:如果应用程序的虚拟目录上启用了匿名访问,则会模拟IUSR_MACHINENAME账户。
3.运行程序,单击“获取文件列表”按钮,如图15-3所示。
我们看到,当前模拟的用户为请求的用户(按Ctrl+Alt+Del组合键也可以看到当前登录的用户信息),由于当前请求的用户为本地的管理员(拥有操作本机d:/test的权限),GridView显示了目录下的所有文件信息。
4.右键单击“我的电脑”,选择“管理”,在本地用户和组下的用户文件夹中找到ASPNET用户,单击属性,如图15-4所示,我们可以看到ASPNET账户隶属于Users这个用户组。
注意:本章所有的例子都是以Windows XP操作系统(IIS 5.1)为例,对于IIS 6.0而言,ASP.NET的默认运行于NetworkService系统账户。
图15-2 配置虚拟目录
图15-3 以模拟方式运行
图15-4 ASPNET账户隶属于Users用户组
那么再来看一下d:/test文件夹的权限,如图15-5所示。
可以看到,Users用户组不具有对这个文件夹的任何权限。那么,如果我们关闭模拟,ASP.NET页面以ASPNET系统账户来执行的话应该就没有权限访问test文件夹了。设置<identity impersonate="false"/>, 然后重新运行页面,如图15-6所示。
图15-5 文件夹的权限 图15-6 关闭账户模拟
单击“获取文件列表”按钮后出现如图15-7所示的异常。
图15-7 ASPNET账户对文件夹的访问被拒绝
如图15-8所示,给test文件夹添加ASPNET系统账户并赋予读取和运行权限。
图15-8 赋予ASPNET系统账户对文件夹的操作权限
重新运行页面后能正常获取文件列表了,如图15-9所示。
图15-9 模拟请求用户
15.2.2 模拟某一个用户
如果你的Web服务器上有多个ASP.NET应用程序,或者你的ASP.NET应用程序需要更高的权限以执行特殊的操作,那么可以为程序设置一个单独的账户。
<?xml version="1.0"?>
<configuration>
<system.web>
<identity impersonate="true"
userName="域/机器名"
password="密码"
/>
</system.web>
</configuration>
在这里,你可以用明文设置用户名和密码,对此就不做过多解释了。需要特别注意的是,你设置的账户需要对以下目录拥有权限:
· ASP.NET临时文件夹。这是ASP.NET动态编译的位置,需要有读写权限。
· 全局程序集缓存(%Windir%/assembly)。这是全局程序集缓存,需要有读取权限。
注意:如果正在运行Windows Server 2003,其中的IIS 6.0配置为运行在辅助进程隔离模式下(默认情况),则可通过将ASP.NET应用程序配置为在自定义应用程序池(在特定的域标识下运行)中运行,然后使用指定的域标识访问资源而无需使用模拟。
15.2.3 使用编程方式进行临时模拟
有的时候可能希望暂时模拟经过身份验证的调用方,可以使用代码进行临时模拟。
1.把先前Page_Load里面的代码封装成一个私有方法并删除Page_Load中的代码。
private void GetIdentityInfo()
{
WindowsIdentity userIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal userPrincipal = new WindowsPrincipal(userIdentity);
Response.Write(string.Format("系统用户标识:{0}<br/>", userPrincipal.
Identity.Name));
Response.Write(string.Format("身份验证类型:{0}<br/>", userPrincipal.
Identity.AuthenticationType));
}
2.修改“获取文件列表”按钮的单击事件处理方法。
protected void btn_GetFileList_Click(object sender, EventArgs e)
{
GetIdentityInfo();
WindowsIdentity userIdentity = (WindowsIdentity)User.Identity;
WindowsPrincipal userPrincipal = new WindowsPrincipal(userIdentity);
WindowsImpersonationContext ctx = null;
try
{
Response.Write("模拟开始<br/>");
ctx = userIdentity.Impersonate();
GetIdentityInfo();
DirectoryInfo di = new DirectoryInfo(@"d:/test");
GridView1.DataSource = di.GetFiles();
GridView1.DataBind();
}
catch
{
}
finally
{
Response.Write("模拟结束<br/>");
if (ctx != null)
ctx.Undo();
GetIdentityInfo();
}
}
我们看到,输出了三次当前用户标识,分别是开始模拟以前,模拟以后和恢复不模拟以后。
3.重新运行程序之前首先修改Web.config文件禁止模拟,然后禁止ASPNET账户对d:/test文件夹的读取权限。运行结果如图15-10所示。
我们看到,虽然在Web.config中禁止了模拟,并且ASPNET账户对文件夹没有读取权限。但是通过编程方式我们临时模拟请求用户成功执行了进行文件夹操作。
图15-10 临时模拟
===============================
// Get the Web application configuration.
System.Configuration.Configuration configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/Test");
// Get the identity section.
IdentitySection identity = (System.Web.Configuration.IdentitySection)configuration.GetSection("system.web/identity");
identity.UserName = "makehtml";
identity.Password = "123";
identity.Impersonate = true;
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cxzhq2002/archive/2007/10/09/1817205.aspx