문제

내 Windows/.NET 보안 스택은 다음과 같습니다.

  • Windows Server 2003 상자에서 로컬 시스템으로 실행되는 Windows 서비스.
  • "기본값"제작 서버 IIS 설정에서 동일한 상자에서 실행되는 .NET 3.5 웹 사이트 (아마 네트워크 서비스 사용자로서?)

기본값 vs2008 Dev 환경에는 ASP.NET 앱에서 호출되는이 하나의 방법이 있습니다.

private static void StopStartReminderService() {

    ServiceController svcController = new ServiceController("eTimeSheetReminderService");

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

제작 서버에서 이것을 실행하면 ServiceController에서 다음 오류가 발생합니다.

출처 : System.ServiceProcess-> System.ServiceProcess.ServiceController-> intptr getServiceHandle (int32) -> System.InValidOperationException 메시지 : 컴퓨터에서 etimesheetreminderservice 서비스를 열 수 없습니다. '.

왜 이런 일이 일어나고 어떻게 해결합니까?

편집하다:

답은 아래에 있으며, 주로 의견에 있지만 명확하게 설명합니다.

  1. 문제는 보안 관련이었으며 NetworkService 계정이 서비스 시작/중지에 충분한 권한이 없기 때문에 발생했습니다.
  2. 로컬 사용자 계정을 만들어 PowerUsers 그룹에 추가했습니다 (이 그룹은 거의 관리자 권한이 있습니다).
  3. 나는 내 웹 앱 전체가 항상 그 사용자를 가장하는 것을 원하지 않으므로 서비스를 조작하는 방법에만 사칭합니다. 코드로 수행하는 데 도움이되는 다음 리소스를 사용 하여이 작업을 수행합니다.

MS KB 기사 그리고 이것은 더 나은 이해를 얻기 위해

노트: 나는 web.config를 통해 가장하지 않고 코드로 수행합니다. 위의 MS KB 기사를 참조하십시오.

도움이 되었습니까?

해결책

이것을 web.config에 추가 해보십시오.

<identity impersonate="true"/>

다른 팁

IIS 특정 서비스를 시작/중지 할 수있는 권한을 부여하려면 :

  • 다운로드 및 설치 subinacl.exe. (최신 버전을 얻으십시오! 일부 리소스 키트에 배포 된 이전 버전은 작동하지 않습니다!)
  • 다음과 유사한 명령을 발행합니다. subinacl /service {yourServiceName} /grant=IIS_WPG=F

이는 내장 IIS_WPG 그룹에 해당 특정 서비스에 대한 완전한 서비스 제어 권한을 부여합니다. (이것은 IIS6 / win2k3에서 작동합니다.) YMMV 최신 버전의 IIS를 위해.)

이것은 나를 흥미롭게 한 좋은 질문이었다 ...

그래서 여기에 내가이 문제를 해결하기 위해 한 일이 있습니다.

  • 1 단계 : 최소한의 권한으로 로컬 컴퓨터에서 Windows 사용자 계정을 만듭니다.
  • 2 단계 : Subinacl.exe를 통해 서비스를 시작하고 중지 할 수있는이 사용자 권한을 부여하십시오.
  • IE subinacl.exe /서비스 WindowsServiceName /grant = pcname testuser = stoe
  • 다우로드 : http://www.microsoft.com/en-za/download/details.aspx?id=23510
  • 3 단계 : 사칭을 사용하여 1 단계에서 생성 된 사용을 가장하여 서비스를 시작하고 중지합니다.

    public const int LOGON32_PROVIDER_DEFAULT = 0;
    
    WindowsImpersonationContext _impersonationContext;
    
    [DllImport("advapi32.dll")]
    // ReSharper disable once MemberCanBePrivate.Global
    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)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern bool RevertToSelf();
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern bool CloseHandle(IntPtr handle);
    
    private bool _impersonate;
    
    public bool ImpersonateValidUser(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)
                {
                    var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    if (_impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        _impersonate = true;
                        return true;
                    }
                }
            }
        }
        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
        _impersonate = false;
        return false;
    }
    
    #region Implementation of IDisposable
    
    
    
    
    #endregion
    
    #region Implementation of IDisposable
    
    private void Dispose(bool dispose)
    {
        if (dispose)
        {
            if (_impersonate)
                _impersonationContext.Undo();
            _impersonationContext.Dispose();
        }
    }
    
    public void Dispose()
    {
        Dispose(true);
    }
    #endregion
    
    public static void StartStopService(bool startService, string serviceName)
    {
        using (var impersonateClass = new Impersonation())
        {
            impersonateClass.ImpersonateValidUser(Settings.Default.LocalUsername, Settings.Default.Domain, Settings.Default.Password);
            using (var sc = new ServiceController(serviceName))
            {
                if (startService)
                    sc.Start();
                else if (sc.CanStop)
                    sc.Stop();
            }
    
        }
    }
    

IIS 8에 대한 업데이트 (아마도 약간 이전 버전)

사용자 그룹 IIS_WPG 더 이상 존재하지 않습니다. 변경되었습니다 iis_iusrs.

또한 서비스를 중지하기 위해 전체 권한을 부여하는 것이 필요하지 않습니다 (F). 서비스를 시작, 중지 및 일시 중지 할 권한이 충분해야합니다. 따라서 명령은 다음과 같습니다.

subinacl /service {yourservicename} /grant = iis_iusrs = top

명령 프롬프트 (바람직하게는 관리자로 실행되기 위해 높음)를 C:\Windows\System32 이 명령을 실행하기 전에 폴더.

또한 subinacl.exe 파일을 C:\Windows\System32 설치 디렉토리에서 오류가있는 경우

직감에 불과하지만 오류는 반드시 보안과 관련이있는 것 같습니다. 프로덕션 서버에서 서비스에 동일한 이름을 부여 했습니까?

웹 응용 프로그램에 데이터베이스가 있고 Windows 서비스에 액세스 할 수있는 경우 DB의 플래그를 사용하여 서비스를 다시 시작할 수 있습니다. 서비스 에서이 플래그를 읽고 바쁘지 않은 경우 다시 시작할 수 있습니다. 서비스 코드를 수정할 수있는 경우에만 해당합니다. 타사 서비스 인 경우 고유 한 Windows 서비스를 작성하고 데이터베이스 구성을 사용하여 서비스를 다시 시작할 수 있습니다. 안전한 방법이며 훨씬 더 유연성과 보안을 제공합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top