퇴근5분전

# WCF 간단예제
 - ABC ( Address<where>, Binding<how>, Contract<what> )
 인터넷 찾아보면 많이 나오니까 ... 건너뛰고 코드로 정리해본다. 

 

# WCF 라이브러리 프로젝트

    . IASvc
    . IBSvc
    . WebSvc : IASvc, IBSvc

 

# Console 프로젝트
      . CustomIDPWDValidator : System.IdentityModel.Selectors.UserNamePasswordValidator 
          - 사용자 정의 로그인 인증 처리 클래스  ( mmc 에서 인증서 복사 ( 개인용 -> 신뢰할수 있는 사용자 ) )
      . Main()에 구현
      {
            서비스 구현
      }

 

# Window 서비스 : 추후에 윈도우 서비스에 올려 사용 

      . 서비스 protected override void OnStart(string[] args)
      {

            ServiceHost = new ( typeof(WCF라이브러리.클래스타입) );

            ServiceHost.Open();

      }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
## windows 인증
 
[[ 서버 ]]
WSHttpBinding bind = new WSHttpBinding(SecurityMode.Message);
bind.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
Uri baseUri = new Uri("http://localhost:9633/Package");
 
using (ServiceHost host = new ServiceHost(typeof(WebSvc), baseUri))
{
    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    host.Description.Behaviors.Add(smb);
 
    // http://localhost:9633/Package/SVC_A/
    host.AddServiceEndpoint(typeof(IASvc), bind, "SVC_A"); // SVC_A 적용.
    // http://localhost:9633/Package/SVC_B/
    host.AddServiceEndpoint(typeof(IBSvc), bind, "SVC_B"); // SVC_B 적용.
 
    Console.WriteLine("host Starting... Stop is press Any key!");
    host.Open();
 
    Console.ReadKey();
    host?.Close();
}
 
 
[[ 클라이언트 ]]
string url = "http://localhost:9633/Package/SVC_A/";
System.ServiceModel.WSHttpBinding binding = 
new System.ServiceModel.WSHttpBinding(System.ServiceModel.SecurityMode.Message);
binding.Security.Message.ClientCredentialType = 
System.ServiceModel.MessageCredentialType.Windows;
System.ServiceModel.EndpointAddress endPoint = 
new System.ServiceModel.EndpointAddress(url);
 
using (PackageService.ASvcClient clnt = new PackageService.ASvcClient(binding, endPoint))
{
    //같은 pc일때는 주석해도 동작! 다른 pc에서 접근시 대상pc의 계정, 비밀번호가 필요함.
    //clnt.ClientCredentials.Windows.ClientCredential = 
new System.Net.NetworkCredential("계정""비밀번호");
    MessageBox.Show(clnt.Hello_ServiceA());
}
// 서비스 B도 위와 동일함. 
 
 
 
 
 
## 사용자정의 인증처리. ( 운용시 X.509 인증서 필요 )
 
[[ 서버 ]]
WSHttpBinding bind = new WSHttpBinding(SecurityMode.Message);
bind.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
Uri baseUri = new Uri("http://localhost:9633/Package");
 
using (ServiceHost host = new ServiceHost(typeof(WebSvc), baseUri))
{
    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    host.Description.Behaviors.Add(smb);
 
    host.Credentials.ServiceCertificate.SetCertificate(
            System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine,
            System.Security.Cryptography.X509Certificates.StoreName.My,
            System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName,
"{등록한 인증서명}");
 
   host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = 
System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
   host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = 
new CustomIDPWDValidator(); // 사용자정의 id,pwd 인증
 
    // http://localhost:9633/Package/SVC_A/
    host.AddServiceEndpoint(typeof(IASvc), bind, "SVC_A"); // SVC_A 적용.
    // http://localhost:9633/Package/SVC_B/
    host.AddServiceEndpoint(typeof(IBSvc), bind, "SVC_B"); // SVC_B 적용.
 
    Console.WriteLine("host Staring... Stop is press Any key!");
    host.Open();
 
    Console.ReadKey();
    host?.Close();
}
 
 ** 테스트 인증서 발급
 (( 비주얼스튜디오에서 솔루션 트리 > 
프로젝트에서 우측버튼 > Open In Terminal 하면 파워쉘 뜨는데 아래 명령어 실행. ))
 
makecert.exe -sr LocalMachine -ss My -a sha1 -n CN={등록한 인증서명} -sky exchange -pe
 
makecert.exe -sr CurrentUser -ss My -a sha1 -n CN=CLNT -sky exchange -pe 
//클라이언트용인데... 실제 테스트 해보면 이것까지 할 필요는 없다.
 
참고 :
https://www.codeproject.com/Articles/36683/9-simple-steps-to-enable-X-509-certificates-on-WCF
 
 
[[ 클라이언트 ]]
string url = "http://localhost:9633/Package/SVC_A/";
System.ServiceModel.WSHttpBinding binding = 
new System.ServiceModel.WSHttpBinding(System.ServiceModel.SecurityMode.Message);
binding.Security.Message.ClientCredentialType = 
System.ServiceModel.MessageCredentialType.UserName;
System.ServiceModel.EndpointAddress endPoint = 
new System.ServiceModel.EndpointAddress(
    new Uri(url),
System.ServiceModel.EndpointIdentity.CreateDnsIdentity("{등록한 인증서명}")); 
//서버 쪽에 설정된 인증서명
 
using (System.ServiceModel.ChannelFactory<PackageService.IASvcChannel> proxy =
    new System.ServiceModel.ChannelFactory<PackageService.IASvcChannel>(binding, endPoint))
{
    /*MESSAGE, USERNAME 일때 로그인 인증*/
    proxy.Credentials.UserName.UserName = "로그인ID";  
//pc계정아님 - wcf통신 인증을 위한 로그인ID - 시스템 사용자id( 예:erp로그인 아이디 )
    proxy.Credentials.UserName.Password = "로그인PWD"
//pc계정아님 - wcf통신 인증을 위한 로그인PWD - 시스템 사용자id pwd( 예:erp로그인 아이디 pwd )
    proxy.Credentials.ServiceCertificate.Authentication.CertificateValidationMode =
        System.ServiceModel.Security.X509CertificateValidationMode.None;
    /*MESSAGE, USERNAME 일때 로그인 인증*/
 
    PackageService.IASvcChannel ch = proxy.CreateChannel();
    MessageBox.Show(ch?.Hello_ServiceA());
}
 
 
 
cs

 

사용자정의 로그인처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CustomIDPWDValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName == "로그인ID" && password == "로그인PWD")
            {                
                Console.WriteLine($"[{userName}] 로그인");
                return;
            }
            else
            {
                throw new System.IdentityModel.Tokens.SecurityTokenException("땡!");
            }
        }
    }
cs

 

서버 서비스쪽에서 클라이언트 ip 정보를 얻을때 아래 remote 객체에 .Address에 있음

1
2
3
4
5
OperationContext oc = OperationContext.Current;
System.ServiceModel.Channels.RemoteEndpointMessageProperty remote =
     oc.IncomingMessageProperties[System.ServiceModel.Channels.RemoteEndpointMessageProperty.Name]
         as System.ServiceModel.Channels.RemoteEndpointMessageProperty;
 
cs

 

서버에서 등록한 인증서명 = {등록한 인증서명} 을

클라이언트에서 EndpointAddress 설정시 url과 EndpointIdentity.CreateDnsIdentity("{등록한 인증서명}")으로

등록하여야 함.

만약 등록하지 않고 다른 코드처럼 하면 아래와 같은 에러가 뜸.

 System.ServiceModel.Security.MessageSecurityException

  HResult=0x80131501

  메시지=보내는 메시지의 ID를 검사하지 못했습니다. 원격 끝점의 필요한 DNS ID가 'localhost'이지만 원격 끝점이 DNS 클래임 '{등록한 인증서명}'을(를) 제공했습니다.

   이 끝점이 올바른 원격 끝점인 경우 채널 프록시를 만들 때 DNS ID '{등록한 인증서명}'을(를) EndpointAddress의 Identity 속성으로 명시적으로 지정하여 이 문제를 해결할 수 있습니다. 

 

서버에서 인증서 등록!! 확인

   1. 커맨드창에 mmc <- 실행.

   2. 실행후 파일 > 스냅인 추가/제거 클릭하면 아래처럼 팝업.

   3. 인증서 추가 > 인증서 스냅인 ( 내 사용자 계정 ) 으로 선택 후 마침.

   4. 테스트 인증서 복사 : 개인 인증서에서 >> 신뢰할수 있는 사용자 인증서로 복사!! 

      : 운영 일때는 조금 다르겠지?

mmc 실행창이 뜬 후 인증서 스냅인 추가.

mmc 스냅인 사용하여 등록... 

docs.microsoft.com/ko-kr/dotnet/framework/wcf/feature-details/how-to-view-certificates-with-the-mmc-snap-in

 

 

방법: MMC 스냅인을 사용 하 여 인증서 보기 - WCF

보안 WCF 클라이언트 또는 서비스는 인증서를 자격 증명으로 사용할 수 있습니다. MMC 플러그 인을 사용 하 여 검사할 수 있는 인증서 저장소의 유형에 대해 알아봅니다.

docs.microsoft.com

 

# 테스트 했을때

 

 

'# 4) .Net ( Vs 2010 ) > 차세대 WPF, WCF' 카테고리의 다른 글

Progress ] 로딩표시 창!  (0) 2015.10.15
WPF] Numeric TextBox  (0) 2015.09.15