커스텀 인증
기본적으로 모든 애플리케이션은 익명의 사용자가 접속할 수 있으며 인증 메커니즘이 없어도 됩니다.
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
서버측
웹서버가 인증 요청을 받은 즉시 쿼리 파라미터들이 유효한지 검사되어야 합니다.
예를 들어, 자격 증명은 데이터베이스에서 저장된 것과 비교 할 수 있습니다.
만약 수신된 파라미터들이 누락되었거나 유효하지 않는 것이면 결과는 { "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.AuthType = CustomAuthenticationType.Custom;
PhotonNetwork.AuthValues.AddAuthParameter("version", version); // HTTP GET
PhotonNetwork.ConnectUsingSettings();
커스텀 인증 URL이 https://example.com
인 경우, https://example.com?version={version}
으로 요청될 것입니다.
인증 공급자 구현에서 버전 정보를 받아 비교해야 합니다.
버전이 허용되는 경우 { "ResultCode": 1 }
을 리턴합니다.
그렇지 않으면 사용자 지정 값(1과 다름)이 포함된 ResultCode
를 메시지와 함께 반환해야 합니다.
예: { "ResultCode": 5, "Message": "Version not allowed." }
.