我曾經成功地使用windows程式成功的創建了一批帶有郵箱的網域帳戶,但是,當我把這段程式碼交給我的一個同事(她負責開發Web應用)遷移到asp.net中後,只能建立網域帳戶,不能建立郵箱。為什麼呢?
我們諮詢了微軟的工程師,他告訴我們,這是由於asp.net的權限不夠,我們應該在asp.net模擬用戶,這樣就可以成功建立。
我將微軟的相關文章摘錄下來:
模擬IIS 驗證的帳戶或用戶
若要在收到ASP.NET 應用程式中每個頁面的每個請求時模擬Microsoft Internet 資訊服務(IIS) 驗證用戶,必須在此應用程式的Web.config 檔案中包含<identity> 標記,並將impersonate 屬性設為true。例如:
<identity impersonate="true" />
為ASP.NET
應用程式的所有請求模擬特定用戶若要為ASP.NET 應用程式的所有頁面上的所有請求模擬特定用戶,可以在該應用程式的Web.config 檔案的<identity> 標記中指定userName 和password 屬性。例如:
<identity impersonate="true" userName="accountname" password="password" />
注意:在執行緒上模擬特定使用者的進程的標識必須具有「作為作業系統的一部分」權限。預設情況下,Aspnet_wp.exe 進程會在名為ASPNET 的電腦帳戶下執行。不過,此帳戶並沒有模擬特定使用者所需的權限。如果您嘗試模擬特定用戶,則會出現錯誤訊息。
若要解決此問題,請使用下列方法之一:
•
為ASPNET 帳戶(權限最低的帳戶)授予「作為作業系統的一部分」權限。
注意:雖然此方法可以解決問題,但Microsoft 不建議使用此方法。
•
在Machine.config 檔案的<processModel> 設定部分中,將執行Aspnet_wp.exe 進程所使用的帳戶變更為System 帳號。
在程式碼中模擬驗證使用者
若要僅在執行程式碼特定部分時模擬驗證使用者(User.Identity),您可以使用下列程式碼。此方法要求身份驗證使用者標識的類型為WindowsIdentity。
Visual Basic .NET
Dim impersonationContext As System.Security.Principal.WindowsImpersonationContext
Dim currentWindowsIdentity As System.Security.Principal.WindowsIdentity
currentWindowsIdentity = CType(User.Identity, System.Security.Principal.WindowsIdentity)
impersonationContext = currentWindowsIdentity.Impersonate()
'Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo()
Visual C# .NET
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
Visual J# .NET
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)get_User().get_Identity()).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
在程式碼中模擬特定用戶
若要僅在執行程式碼特定部分時模擬特定用戶,請使用以下程式碼:
Visual Basic .NET
<%@ Page Language="VB" %>
<%@ Import Namespace = "System.Web" %>
<%@ Import Namespace = "System.Web.Security" %>
<%@ Import Namespace = "System.Security.Principal" %>
<%@ Import Namespace = "System.Runtime.InteropServices" %>
<script runat=server>
Dim LOGON32_LOGON_INTERACTIVE As Integer = 2
Dim LOGON32_PROVIDER_DEFAULT As Integer = 0
Dim impersonationContext As WindowsImpersonationContext
Declare Function LogonUserA Lib "advapi32.dll" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, _
ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, _
ByVal dwLogonProvider As Integer, _
ByRef phToken As IntPtr) As Integer
Declare Auto Function DuplicateToken Lib "advapi32.dll" ( _
ByVal ExistingTokenHandle As IntPtr, _
ByVal ImpersonationLevel As Integer, _
ByRef DuplicateTokenHandle As IntPtr) As Integer
Declare Auto Function RevertToSelf Lib "advapi32.dll" () As Long
Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Long
Public Sub Page_Load(ByVal s As Object, ByVal e As EventArgs)
If impersonateValidUser("username", "domain", "password") Then
'Insert your code that runs under the security context of a specific user here.
undoImpersonation()
Else
'Your impersonation failed. Therefore, include a fail-safe mechanism here.
End If
End Sub
Private Function impersonateValidUser(ByVal userName As String, _
ByVal domain As String, ByVal password As String) As Boolean
Dim tempWindowsIdentity As WindowsIdentity
Dim token As IntPtr = IntPtr.Zero
Dim tokenDuplicate As IntPtr = IntPtr.Zero
impersonateValidUser = False
If RevertToSelf() Then
If LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
impersonationContext = tempWindowsIdentity.Impersonate()
If Not impersonationContext Is Nothing Then
impersonateValidUser = True
End If
End If
End If
End If
If Not tokenDuplicate.Equals(IntPtr.Zero) Then
CloseHandle(tokenDuplicate)
End If
If Not token.Equals(IntPtr.Zero) Then
CloseHandle(token)
End If
End Function
Private Sub undoImpersonation()
impersonationContext.Undo()
End Sub
</script>
Visual C# .NET
<%@ Page Language="C#"%>
<%@ Import Namespace = "System.Web" %>
<%@ Import Namespace = "System.Web.Security" %>
<%@ Import Namespace = "System.Security.Principal" %>
<%@ Import Namespace = "System.Runtime.InteropServices" %>
<script runat=server>
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
[DllImport("advapi32.dll")]
public 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)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
public void Page_Load(Object s, EventArgs e)
{
if(impersonateValidUser("username", "domain", "password"))
{
//Insert your code that runs under the security context of a specific user here.
undoImpersonation();
}
else
{
//Your impersonation failed. Therefore, include a fail-safe mechanism here.
}
}
private bool impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
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)
{
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;
}
private void undoImpersonation()
{
impersonationContext.Undo();
}
</script>
Visual J# .NET
<%@ Page language="VJ#" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Web.Security" %>
<%@ Import Namespace="System.Security.Principal" %>
<%@ Import Namespace="System.Runtime.InteropServices" %>
<script runat=server>
public static int LOGON32_LOGON_INTERACTIVE = 2;
public static int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
/** @attribute DllImport("advapi32.dll") */
public static native int LogonUserA(String lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider,
System.IntPtr[] phToken);
/** @attribute DllImport("advapi32.dll",
CharSet=CharSet.Auto, SetLastError=true) */
public static native int DuplicateToken(System.IntPtr hToken,
int impersonationLevel,
System.IntPtr[] hNewToken);
/** @attribute DllImport("kernel32.dll",CharSet=CharSet.Auto) */
public static native boolean CloseHandle(System.IntPtr[] handle);
/** @attribute DllImport("advapi32.dll",
CharSet=CharSet.Auto,SetLastError=true) */
public static native boolean RevertToSelf();
public void Page_Load(Object s, System.EventArgs e)
{
if(impersonateValidUser("username", "domain", " password"))
{
//Insert your code that runs under the security context of a specific user here.
undoImpersonation();
}
else
{
//Your impersonation failed. Therefore, include a fail-safe mechanism here.
}
}
private boolean impersonateValidUser(String userName, String domain, String password)
{
WindowsIdentity tempWindowsIdentity;
System.IntPtr[] token = new System.IntPtr[1];
System.IntPtr[] tokenDuplicate = new System.IntPtr[1];
if(RevertToSelf())
{
if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, token) != 0)
{
if(DuplicateToken(token[0], 2, tokenDuplicate) != 0)
{
tempWindowsIdentity = new WindowsIdentity(tokenDuplicate[0]);
impersonationContext = tempWindowsIdentity.Impersonate();
if (impersonationContext != null)
{
CloseHandle(tokenDuplicate);
CloseHandle(token);
return true;
}
}
}
}
if(!token[0].Equals(System.IntPtr.Zero))
CloseHandle(token);
if(!tokenDuplicate[0].Equals(System.IntPtr.Zero))
CloseHandle(tokenDuplicate);
return false;
}
private void undoImpersonation()
{
impersonationContext.Undo();
}
</script>
注意:在執行緒上模擬特定使用者的進程的標識必須具有「作為作業系統的一部分」權限。預設情況下,Aspnet_wp.exe 進程會在名為ASPNET 的電腦帳戶下執行。不過,此帳戶並沒有模擬特定使用者所需的權限。如果您嘗試模擬特定用戶,則會出現錯誤訊息。
若要解決此問題,請使用下列方法之一:
•
為ASPNET 帳戶授予「作為作業系統的一部分」權限。
•
在Machine.config 檔案的<processModel> 設定部分中,將執行Aspnet_wp.exe 進程所使用的帳戶變更為System 帳號。