使用正确的权限在ASP.NET / C#中启动服务

时间:2011-05-20 10:01:15

标签: c# asp.net windows-services permissions servicecontroller

在我的网站上(用ASP.NET / C#编写)我希望中级人员能够启动某项服务。我的代码是:

    ServiceController svcController = new ServiceController("InvidualFileConversion");

    if (svcController != null)
    {
        try
        {
            svcController.Stop();
            svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
            svcController.Start();
        }
        catch (Exception ex)
        {
            // error
        }
    }

现在,当我运行此操作时,我收到错误“无法在计算机上打开InvidualFileConversion服务”,并附加消息:“Acces被拒绝”。

我知道这是权限问题,但如何为自己提供适当的权限? 不要在我应该写的地方找到答案:因为我已经尝试了它并且它不起作用。此外,我认为,当我只需要这几行代码时,这并不是为整个网站设置此功能的最佳方式。

编辑:我在我的代码中添加了这个,但它仍然不起作用,我在同一个地方得到了相同的异常。现在它看起来像这样:

protected void ConvertLink_OnClick(object sender, EventArgs e)
{
    //convert();
    try
    {
        //--need to impersonate with the user having appropriate rights to start the service
        Impersonate objImpersonate = new Impersonate(domainName, userName, userPassword);
        if (objImpersonate.impersonateValidUser())
        {
            //--write code to start/stop the window service
            startWindowsService();
            objImpersonate.undoImpersonation();
        }
    }
    catch (Exception Ex)
    { Response.Write(Ex.Message + Ex.InnerException.Message); }
}

private void startWindowsService()
{
    ServiceController svcController = new ServiceController("InvidualFileConversion");

    if (svcController != null)
    {
        try
        {
            svcController.Stop();
            svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
            svcController.Start();
        }
        catch (Exception ex)
        {
            // error
        }
    }
}

我有一个如下所示的Impersonate类:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Security.Principal;
using System.Runtime.InteropServices;

/// <summary>
/// Summary description for Impersonate
/// </summary>
public class Impersonate
{

#region "Class Members"
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_PROVIDER_DEFAULT = 0;
WindowsImpersonationContext impersonationContext;
#endregion

#region "Class Properties"
public string domainName { get; set; }
public string userName { get; set; }
public string userPassword { get; set; }
#endregion

public Impersonate()
{
    //
    // TODO: Add constructor logic here
    //
}
public Impersonate(string domainName, string userName, string userPassword)
{
    this.domainName = domainName;
    this.userName = userName;
    this.userPassword = userPassword;
}

#region "Impersonation Code"
[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 bool impersonateValidUser()
{
    WindowsIdentity tempWindowsIdentity;
    IntPtr token = IntPtr.Zero;
    IntPtr tokenDuplicate = IntPtr.Zero;

    if (RevertToSelf())
    {
        if (LogonUserA(this.userName, this.domainName, this.userPassword, 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;
}

public void undoImpersonation()
{
    impersonationContext.Undo();
}
#endregion
}

所以验证工作有效,但没有解决我的问题..我猜仍然存在权限问题..我该怎么做才能改变它?

编辑2:我接下来的步骤涉及到:

  1. 创建一个应用程序池,其中标识设置为用户(属于管理员组的成员)。
  2. 将服务“登录”设置为同一用户。
  3. 再次运行网络应用后,仍然会失败..
  4. 然而如果我在管理员帐户中输入代码中的凭据,它就可以工作..(即使我没有在应用程序池和服务中使用管理员......)< / p>

    换句话说,我可以通过管理员帐户获得我想要的内容,但不能使用我自己创建并拥有管理员权限的帐户。我仍然希望与我自己创建的用户合作,因为我认为提供管理员凭据并不安全。

    在旁注中,在我工作的服务器上,我有一个具有管理员权限但不是“管理员”帐户的帐户。

    编辑3:这变得很奇怪。我现在似乎工作但是:   - 没有模拟方法(它没有工作)。   - 我刚刚做了Rob说的话。我有自己的应用程序池和我定义的用户。 Windows服务也指定了该用户。 (用户收到了“登录身份服务”权限)   - 有了它,它似乎工作。   - 但如果通过我的网站调试我仍然被拒绝访问。但如果只是通过浏览器访问我的网站及其ip,我可以启动该服务。

    总结一下:   - 模拟方法不起作用。   - 如果服务还指定了用户,则只使用自创的应用程序池与当前用户一起工作。但它在调试模式下不起作用(仍有Acces Denied)。

    这篇文章变得越来越大,我想知道是否仍然真的读它..但也许有人可以提供给我任何细节?我担心它将来会在某个地方再次失败。

    任何评论将不胜感激! 弗洛

1 个答案:

答案 0 :(得分:2)

您必须确保您的网站在有足够权限启动该服务的用户下运行。 还要确保在IIS上禁用匿名身份验证 一种好方法是创建一个有权在服务器Web上启动服务的用户,然后创建一个在该用户下运行的应用程序池。然后,您必须使您的网站使用该应用程序池。使用此方法,所有网站都将在您刚刚创建的用户下运行。 如果您想要更精细,您仍然可以创建具有启动服务权限的用户,但不是将其用于应用程序池,而是只能使用模拟使该用户在该用户下运行需要启动服务的页面。您只能对此方法使用imporsonation功能!

有关详细信息,请查看以下链接:

http://forums.asp.net/t/1137962.aspx/1

http://support.microsoft.com/kb/306158