WCF 관련 샘플 ( 윈도우 인증, 사용자정의 인증 )
# 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 스냅인 사용하여 등록...
# 테스트 했을때
'# 4) .Net ( Vs 2010 ) > 차세대 WPF, WCF' 카테고리의 다른 글
Progress ] 로딩표시 창! (0) | 2015.10.15 |
---|---|
WPF] Numeric TextBox (0) | 2015.09.15 |