커스텀 인증
기본적으로 모든 애플리케이션은 익명의 사용자가 접속할 수 있으며 인증 메커니즘이 없어도 됩니다.
Photon 은 Photon 애플리케이션에 대해 커스텀 인증을 구현할 수 있는 옵션을 제공하고 있습니다.
Photon의 커스텀 인증은 유연합니다.
이에 대해서 완전 개인화된 솔루션 뿐만 아니라 잘 알려진 제3자 인증 공급자를 지원하고 있습니다.
- Exit Games에서 호스트 하고 있는 페이스북 인증 공급자.이 페이지를 확인 해 보세요
- 커스텀 인증 공급자, 구축 - 내가 호스트 할 수 도 있음.
Git 리포지토리에서 인증 공급자 구현에 대한 샘플을 제공 하고 있습니다.
리포지토리를 마음껏 포크 하시고 요청을 저희에게 보내 주세요.
GitHub 에서 소스를 볼 수 있습니다.
인증 흐름
다음 단계들에는 인증 프로세스의 일반적인 흐름을 설명하고 있습니다.
- 인증 공급자가 사용할 정보와 인증에 필요한 데이터를
Connect()
할때 같이 Photon 서버로 클라이언트가 전달합니다. - Photon 서버는 애플리케이션에 필요한 인증 공급자를 얻고 다음 단계 중의 하나를 처리합니다.
- 인증 공급자 환경 설정을 찾았으면 -> 인증은 단계 3에서 처리됩니다.
- 인증 공급자 환경 설정을 찾지 못했으면 -> 애플리케이션 설정에 따라 클라이언트는 접속이 허용 또는 거부됩니다.
- Photon 서버는
Connect()
에서 전달된 인증 정보를 가지고 인증 공급자를 호출 합니다.- 인증 공급자가 온라인의 경우 -> 인증은 단계 4로 처리됩니다.
- 인증 공급자가 오프라인의 경우 -> 상응하는 공급자 설정에 따라 클라이언트가 접속 허용 또는 거부 됩니다.
- 인증 공급자는 인증 정보를 처리하고 Photon 서버로 결과를 리턴해 줍니다.
- 인증 결과에 따라서 클라이언트는 성공적으로 인증 또는 거부 되게 될 것입니다.
구현
클라이언트 측
클라이언트 측에서 LoadBalancing API는 커스텀 인증을 처리할 것입니다 - 관련된 파라미터와 타겟 커스텀 인증 서비스를 한번 설정 해 주기만 하면 됩니다.
설정이 완료되었으면 연결과 연속적인 오류를 처리할 수 있습니다.
예제:
C#
AuthenticationValues authValues = new AuthenticationValues();
authValues.AuthType = CustomAuthenticationType.Custom;
authValues.AddAuthParameter("user", userId);
authValues.AddAuthParameter("pass", pass);
authValues.UserId = userId; // this is required when you set UserId directly from client and not from web service
PhotonNetwork.AuthValues = authValues;
// connect
데모
PUN Free와 PUN+ 유니티 패키지들은 커스텀 인증을 사용하는 데모가 포함되어 있습니다.
새로운 빈 프로젝트에 패키지를 임포트 하고 실행하면 "Demo Hub"를 사용할 수 있는 데모를 보여 주어야 합니다.
"Friends & Custom Auth Demo"를 고르세요.
"DemoFriends-Scene"은 간단한 사용자 로그인 양식을 표시합니다.
"GUICustomAuth.cs" 파일에 있는 OnGUI()
메소드를 확인 해보세요.
"Login with Custom Authentication" 버튼 코드는 AuthValues
를 설정하고 연결합니다.
설정된 서비스에 커스텀 인증 요청을 자동으로 트리거 하는 것입니다.
동일 파일 안의 OnCustomAuthenticationFailed
콜백 메소드에 주목해보세요.
사용자 인증이 실패한 경우에 대한 처리를 구현하고 있습니다.
서버측
웹서버가 인증 요청을 받은 즉시 쿼리 파라미터들이 유효한지 검사되어야 합니다.
예를 들어, 자격 증명은 데이터베이스에서 저장된 것과 비교 할 수 있습니다.
만약 수신된 파라미터들이 누락되었거나 유효하지 않는 것이면 결과는 { "ResultCode": 3, "Message": "Invalid parameters." }
로 리턴되어야 합니다.
검증이 끝난 후 결과는 다음과 같이 리턴되어야 합니다:
- 성공:
{ "ResultCode": 1, "UserId": <userId> }
- 실패:
{ "ResultCode": 2, "Message": "Authentication failed. Wrong credentials." }
고급 기능
사용자의 인증 이외에 인증 공급자로부터 추가적인 정보가 리턴 될 수 있습니다.
이렇게 하기 위해서 사용자는 클라이언트와 인증자 역할을 하는 웹 서비스 간에 특정한 프로토콜을 만들어야 합니다.
서버로 데이터 전송
가장 쉽고 간단한 방법은 "모두 아니면 아무것도(All or noting)" 전략입니다:
클라이언트에게 변수의 정적 숫자를 리턴할지 하지 않을지를 선택하세요.
하지만 클라이언트가 요청한 것을 기반으로 "온-디멘드" 데이터를 리턴하는 웹서비스와 같은 일부 유즈 케이스에서는 더 복잡한 접근법이 요구됩니다.
다음의 하위 섹션에서는 클라이언트가 웹서비스로 어떻게 데이터를 전송하는지에 대해 설명합니다.
데이터는 인증과 추가 파라미터의 인증에 필요한 자격 증명이 될 수 있습니다.
추가 파라미터들은 인증 응답의 리턴으로 서버측으로 부터 사용할 수 있는 데이터를 요청하기 위해서 사용 될 수 있습니다.
이것은 추가적인 API 호출이 없고 로그인 흐름이 간단 해지므로 매우 유용합니다.
아주 드문 경우지만 인증할 때 수많은 데이터가 필요하여 부하가 크게 걸릴 수도 있습니다.
다른 한편으로 대부분의 웹서버는 쿼리 스트링 또는 URL의 길이는 제한을 가지고 있습니다.
이 사항 때문에 Photon 은 C# SDK에서 AuthenticationValues.AuthPostData
를 명시적으로 설정하여 클라이언트에서 오는 HTTP 메소드를 POST로 변경을 제안하는 것입니다.
후자는 string
또는 byte[]
또는 Dictionary<string, object>
타입이 될 수 있습니다.
Dictionary<string, object>
의 경우, 페이로드는 JSON 문자열로 변환된고 HTTP 요청의 Content-Type는 "applicaton/json"입니다.
C# SDK에서, AuthenticationValues
클래스는 각 타입에 대하여 두 개의 setter 를 제공 하고 있습니다.
이것은 필요사항 또는 제약사항이 될 수 있으므로 웹 서비스에게 POST 메소드 인증 요청을 선택한 누구라도 가능하도록 해야 합니다.
다시 말하자면, 인증 파라미터를 전송하기 위해서 쿼리 스트링을 사용하던 POST 데이터를 사용하던 둘 다 사용하든지 관계없습니다.
다음 테이블에는 가능한 조합을 보여 주고 있습니다.
AuthPostData | AuthGetParameters | HTTP 메소드 |
---|---|---|
null | * | GET |
빈 문자열 | * | GET |
string (null 아님, 빈 문자열 아님) | * | POST |
byte[] (null 아님, 빈 문자열 가능) | * | POST |
Dictionary<string, object> (null 아님, 빈 문자열 가능) | * | POST (Content-Type="application/json") |
클라이언트에게 데이터 리턴
Photon 서버가 클라이언트와 웹 서비스 사이의 프록시이기 때문에 Photon 서버에 의해서 처리되는 변수들에 대해서 주의해야 합니다.
Photon 서버에 의해 수신되는 HTTP 수신 응답과 같이 웹 서버는 ResultCode
와 선택적으로 Message
를 포함한 JSON 객체를 리턴해야 합니다.
추가적으로 인증하는 동안에 웹 서비스로부터 수신할 수 있는 목록이 있습니다.
UserId
:
인증 자체의 파라미터로 사용되거나 클라이언트 측에서 요구 될 수 도 있습니다.
이것은 Photon 서버에 의해 수신될 때 클라이언트에게 항상 포워드 됩니다.
만약 초기에AuthenticationValues.UserId
값이 설정되어 있지 않으면 클라이언트로 다시 전송될 때 UserId는 무작위로 생성되어 전송됩니다.
이렇게 하면 클라이언트 내에서UserId
의 값을 오버라이드하고 이후에 변경될 수 없습니다.
ResultCode
값이 1인 경우에만 리턴되어야 합니다.
예:{ "ResultCode": 1, "UserId": "SomeUniqueStringId" }
Nickname
:
인증 자체의 파라미터로 사용되거나 클라이언트 측에서 요구될 수도 있습니다.
웹 서비스로부터 리턴 될 때 이것은 클라이언트의Nickname
을 오버라이드 하게 됩니다.
이Nickname
은 이후에 클라이언트에서 변경될 수 있습니다.
ResultCode
값이 1인 경우에만 리턴되어야 합니다.
예:{ "ResultCode": 1, "UserId": "SomeUniqueStringId", "Nickname": "SomeNiceDisplayName" }
AuthCookie
:
보안 데이터라고도 불리우는 이것은 웹 서비스에 의해서 리턴되는 JSON 객체이지만 수신된 암호화된 토큰에 임베드 되어 있을 것이므로 클라이언트 측에서 접근할 수 없을 것입니다.
나중에 Webhook 또는 WebRPC HTTP 요청으로 전송될 수도 있습니다.
ResultCode
값이 1인 경우에만 리턴되어야 합니다.
예:{ "ResultCode": 1, "UserId": "SomeUniqueStringId", "AuthCookie": { "SecretKey": "SecretValue", "Check": true, "AnotherKey": 1000 } }
{% endif %}Data
: JSON 객체로 클라이언트에게 리턴되어야 하는 모든 추가적인 값을 가지고 있습니다.
중첩된 배열 또는 객체들이 지원되지 않는다는 것에 주의하세요.
ResultCode
값이 1 또는 0인 경우에만 리턴되어야 합니다.
예:{ "ResultCode": 0, "Data": { "S": "Vpqmazljnbr=", "A": [ 1, -5, 9 ] } }
ResultCode
가 필수 리턴 변수이며 나머지 값은 다 선택적인 것들입니다.
다음의 테이블에서 웹 서버가 리턴해 줄 수 있는 것에 대해 요약해 놓았습니다.
ResultCode | Description | UserId | Nickname | Data | AuthCookie |
---|---|---|---|---|---|
0 | 인증 미완료, 데이터만 리턴됨.* | ||||
1 | 인증 성공. | (optional) | (optional) | (optional) | (optional) |
2 | 인증 실패. 잘못된 자격증명. | ||||
3 | 잘못된 파라미터. |
*: OAuth 2.0 구현 및 이중 인증에 유용하다는 것을 나타냅니다.
클라이언트로 온 데이터 읽기
다음 코드는 인증 응답을 해석할 때 어떻게 데이터 타입을 변환하는지 보여 줍니다:
이 콜백은 사용자 정의 서버로 인증을 하는 동안 리턴된 선택적인 사용자 정의 Data
를 가져오는데 사용됩니다.
C#
void OnCustomAuthenticationResponse(Dictionary<string, object> data)
{
// here you can access the returned data
}
데이터 타입 변환
이 섹션에서는 Photon 서버와 웹 서비스간의 데이터 교환의 타입에 대해서만 설명합니다.
클라이언트와 Photon 서버간의 데이터 타입에 대해서는 Photon 의 직렬화 페이지를 참고 하시기 바랍니다.
Photon 서버 -> 웹 서비스
C# / .NET (Photon 지원 타입) | JavaScript / JSON |
---|---|
byte
|
number |
short
|
|
int
|
|
long
|
|
double
|
|
bool
|
bool |
string
|
string |
byte[] (byte 배열 length < short.MaxValue )
|
string (Base64 encoded) |
T[] (array of supported type T, length < short.MaxValue )
|
array |
Hashtable (of supported types, count < short.MaxValue , preferably Photon implementation)
|
object |
Dictionary (keys and values of supported types, count < short.MaxValue )
|
object |
null
|
null
|
샘플 요청 데이터 (타입들이 연결되어 있습니다)
Photon 서버 전송:
JavaScript
{
"(Dictionary<String,Object>)Dictionary":{
"(Int32)dk_int":"1",
"(String)dk_str":"dv2",
"(Boolean)dk_bool":"True"
},
"(Hashtable)Hashtable":{
"(Byte)hk_byte":"255",
"(Object[])hk_array":[
"(Object)0",
"(Object)xy",
"(Object)False"
],
"hk_null":"null"
},
"null":"null",
"(String[])string[]":[
"(String)PUN",
"(String)TB",
"(String)RT",
"(String)Bolt",
"(String)Chat"
],
"(Byte[])byte[]":[
"(Byte)255",
"(Byte)0"
],
"(Int16[])short[]":[
"(Int16)-32768",
"(Int16)32767"
],
"(Int32[])int[]":[
"(Int32)-2147483648",
"(Int32)2147483647"
],
"(Int64[])long[]":[
"(Int64)-9223372036854775808",
"(Int64)9223372036854775807"
],
"(Single[])float[]":[
"(Single)-3.402823E+38",
"(Single)3.402823E+38"
],
"(Double[])double[]":[
"(Double)-1.79769313486232E+308",
"(Double)1.79769313486232E+308"
],
"(Boolean[])bool[]":[
"(Boolean)True",
"(Boolean)False"
]
}
Web 서비스 수신:
JavaScript
{
"(object)Dictionary":{
"dk_int":"(number)1",
"dk_str":"(string)dv2",
"dk_bool":"(boolean)true"
},
"(object)Hashtable":{
"hk_byte":"(number)255",
"hk_null":null,
"hk_array":[
"(number)0",
"(string)xy",
"(boolean)false"
]
},
"null":null,
"(array)string[]":[
"(string)PUN",
"(string)TB",
"(string)RT",
"(string)Bolt",
"(string)Chat"
],
"byte[]":"(string)/wA=",
"(array)short[]":[
"(number)-32768",
"(number)32767"
],
"(array)int[]":[
"(number)-2147483648",
"(number)2147483647"
],
"(array)long[]":[
"(number)-9223372036854776000",
"(number)9223372036854776000"
],
"(array)float[]":[
"(number)-3.40282347e+38",
"(number)3.40282347e+38"
],
"(array)double[]":[
"(number)-1.7976931348623157e+308",
"(number)1.7976931348623157e+308"
],
"(array)bool[]":[
"(boolean)true",
"(boolean)false"
]
}
웹 서비스 -> Photon 서버
C#/.Net 에서 JavaScript/JSON 타입과 각각 대응하는 테이블입니다.
Here is a table that matches each JavaScript/JSON type to its equivalent one in C#/.Net :
JavaScript / JSON | C# / .Net |
---|---|
object |
Dictionary
|
array |
object[] (array of objects)
|
number (integral) |
long
|
number (floating) |
double
|
string |
string
|
boolean |
bool
|
null (not a type)
|
null
|
undefined (when sent)
|
null
|
응답 데이터 샘플 (타입들이 연결되어 있습니다)
Web Service 전송:
JavaScript
{
"(object)number": {
"MAX_VALUE": "(number)1.7976931348623157e+308",
"MIN_VALUE": "(number)5e-324"
},
"(object)object": {
"string": "(string)xyz",
"null": null,
"bool": "(boolean)false",
"undefined": "(undefined)undefined",
"number": "(number)-3.14"
},
"(array)array": [
"(string)xyz",
"(number)0",
"(boolean)true",
null,
"(undefined)undefined"
]
}
Photon Server 수신:
JavaScript
{
"(Dictionary<String,Object>)number":{
"(Double)MAX_VALUE":"1.79769313486232E+308",
"(Double)MIN_VALUE":"4.94065645841247E-324"
},
"(Dictionary<String,Object>)object":{
"(String)string":"xyz",
"null":"null",
"(Boolean)bool":"False",
"(Double)number":"-3.14"
},
"(Object[])array":[
"(Object)xyz",
"(Object)0",
"(Object)True",
"null",
"null"
]
}
문제 해결
사용자 정의 인증이 실패하면, 다음의 콜백이 트리거 됩니다:
C#
void OnCustomAuthenticationFailed(string debugMessage)
{
// The `debugMessage` could be what the authentication provider returned.
}
관리 화면에서 구성한 인증 URL이 일부 HTTP 오류를 반환하는 경우 Photon 서버는 일부 오버헤드를 방지하기 위해 인증 호출을 잠시 일시 중지합니다.
URL을 구성하거나 테스트할 때 이 "백오프" 시간을 고려하십시오.
모범 사례
- 인증 공급자로부터 반환된 결과에는, 특히 오류 발생 시 읽을 수 있는
메시지
가 포함되어야 합니다.
이렇게 하면 힘든 디버깅 과정을 줄일 수 있습니다. - 관리 화면에서 정적 키/값이 클라이언트에서 설정될 수 없도록 하세요.
쿼리 스트링 결과에 중복 키를 방지하게 해 줍니다. - 보안상의 이유로 패스워드를 인증 파라미터로 일반 텍스트로 전송하지 마시기 바랍니다.
- Photon 관리 화면에서 쿼리 문자열 파라미터를 설정하는 것을 권장하고 있습니다.
이 방식을 통해 요청의 원천을 확인할 수 있습니다. AuthenticationValues
를 이용하여 파라미터를 설정하여AuthGetParameters
의 값에 직접적인 영향이 가지 않도록 해주세요.
이렇게 하면 잘못된 쿼리 스트링을 방지할 수 있습니다.
유즈 케이스 예제: Block 이전 클라이언터 버전
커스텀 인증을 사용하여 이전 버전(또는 예기치 않은 버전)을 사용하는 클라이언트에서 들어오는 연결을 거부하고 사용자에게 업데이트를 요청할 수 있도록 특정 오류를 리턴할 수 있습니다.
이렇게 하려면 커스텀 인증 요청에서 버전을 전송해야 합니다. 쿼리 문자열 매개 변수 또는 POST 데이터 인수로 할지 결정하는 것은 사용자의 몫입니다.
아래 예에서는 쿼리 문자열 매개 변수를 사용합니다:
C#
string version = PhotonNetwork.gameVersion;
// string version = Application.version; // if you use the version from Unity
PhotonNetwork.AuthValues = new AuthenticationValues();
PhotonNetwork.AuthValues = CustomAuthenticationType.Custom;
PhotonNetwork.AuthValues.AddAuthParameter("version", version); // HTTP GET
PhotonNetwork.ConnectUsingSettings(version);
커스텀 인증 URL이 https://example.com
인 경우, https://example.com?version={version}
으로 요청될 것입니다.
인증 공급자 구현에서 버전 정보를 받아 비교해야 합니다.
버전이 허용되는 경우 { "ResultCode": 1 }
을 리턴합니다.
그렇지 않으면 사용자 지정 값(1과 다름)이 포함된 ResultCode
를 메시지와 함께 반환해야 합니다.
예: { "ResultCode": 5, "Message": "Version not allowed." }
.