Custom Authentication
預設下,所有應用程式都允許匿名使用者連接,並且沒有任何身份驗證機制。
Photon提供了為Photon應用程式實作自訂身份驗證的選項。
Photon的自訂身份驗證非常靈活。
它支援知名的第三方身份驗證提供者以及完全個人化的解決方案。
*Facebook身份驗證提供者,由Exit Games託管。查看此頁面
*自訂身份驗證提供者,由您組建,也可能由您託管。
我們透過Git存儲庫提供身份驗證提供者的範例實作。
請隨時分支存儲庫並向我們發送您的拉取請求。
您可以在GitHub上找到原始程式碼。
身份驗證流程
以下步驟描述了身份驗證過程的一般流程。
- 您的客戶端使用
Connect()
將有關使用哪個身份驗證提供者的資訊和必要的身份驗證資料傳遞給Photon伺服器。 - Photon伺服器為您的應用程式獲取所需的身份驗證提供者,並採取以下步驟之一
- 找到身份驗證提供者配置->身份驗證繼續執行步驟3。
- 找不到身份驗證提供者配置->根據應用程式的設定,客戶端將被允許連接或拒絕
- Photon伺服器使用透過
Connect()
傳遞的身份驗證資訊調用身份驗證提供者。- 身份驗證提供者在線上->身份驗證繼續執行步驟4。
- 身份驗證提供者處於離線狀態->根據相應的提供者設定,客戶端將被允許連接或拒絕。
- 身份驗證提供者處理驗證資訊並將結果傳回給Photon伺服器
- 根據身份驗證結果,客戶端將被成功驗證或拒絕
實作
客戶端側
在客戶端側,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
伺服器側
一旦web伺服器收到身份驗證請求,就應該檢查和驗證査詢參數。
例如,可以將憑證與存儲在資料庫中的現有憑證進行比較。
如果接收到的參數缺失或無效,則返回的結果應為{ "ResultCode": 3, "Message": "Invalid parameters." }
完成驗證後,應按如下方式返回結果:
- 成功:
{ "ResultCode": 1, "UserId": <userId> }
- 失敗:
{ "ResultCode": 2, "Message": "Authentication failed. Wrong credentials." }
高級功能
除了對用戶進行身份驗證外,還可以從身份驗證提供者返回額外的資訊。
為了做到這一點,用戶應該在客戶端和扮演「身份驗證器」角色的web服務之間建立某種協定。
向伺服器發送資料
最簡單的方法是「要麼全有要麼全無」的策略:
選擇是否向客戶端返回靜態數量的變數。
但有些用例需要一種更複雜的方法,即web服務根據客戶端的請求「按需」返回資料。
本小節解釋了客戶端如何向web服務發送資料。
資料可以是身份驗證所需的憑證,也可以加上任何額外的參數。
除其他事項外,額外的參數可用於請求在身份驗證回應中返回伺服器端的可用的資料。
這非常有用,因為它可以節省額外的API調用並簡化登入工作流程。
在極少數情況下,身份驗證可能需要大量資料。
另一方面,大多數web伺服器對査詢字串中使用的字元數或URL長度有限制。
這就是為什麼Photon提供了從客戶端將HTTP方法更改為POST的可能性,在C# SDK中,這是通過顯式設定AuthenticationValues.AuthPostData
欄位為一個值來完成的。
後者的類型可以是string
、byte[]
或Dictionary<string, object>
。
在Dictionary<string, object>
的情況下,載荷將被轉換為JSON字串,而HTTP請求的內容-類型將被設定為「applicaton/json」。
在C# SDK中,AuthenticationValues
類別為每種支援的類型提供了setter方法。
由於這可能是一個要求或約束,因此POST方法選項也適用於選擇以POST方法從web服務接收身份驗證請求的任何人。
換句話說,要發送身份驗證參數,您可以自由使用査詢字串或POST資料,或兩者兼而有之。
下表給出了可能的組合。
AuthPostData | AuthGetParameters | HTTP方法 |
---|---|---|
空值 | * | GET |
空的字串 | * | GET |
字串(不是空值,不是空的) | * | POST |
位元[](不是空值,可以是空的) | * | POST |
字典<字串,物件>(不是空值,可以是空的) | * | POST (內容-類型="application/json") |
將資料返回給客戶端
由於Photon伺服器是客戶端和web服務之間的代理,因此您應該注意Photon伺服器可以處理的變數。
與Photon伺服器收到的所有HTTP傳入回應一樣,web伺服器應返回一個JSON物件,其中包括一個ResultCode
和一個可選的Message
。
此外,這裡列出了Photon伺服器在身份驗證期間可以從web服務中獲得什麼。
UserId
:
這可以用作身份驗證本身的參數,也可以從客戶端請求。
當Photon伺服器接收到該消息時,它始終會轉發給客戶端。
否則,如果AuthenticationValues.UserId
最初沒有設定,隨機生成的UserId將被發送回客戶端。
這將覆寫客戶端中的UserId
值,且此後無法更改。
僅當ResultCode
值為1時,才應返回此值。
示例:{ "ResultCode": 1, "UserId": "SomeUniqueStringId" }
Nickname
:
這可以用作身份驗證本身的參數,也可以從客戶端側請求。
當從web服務返回時,這將覆寫客戶端中的Nickname
值。
在那之後,客戶端仍可更新Nickname
。
僅當ResultCode
值為1時,才應返回此值。
示例:{ "ResultCode": 1, "UserId": "SomeUniqueStringId", "Nickname": "SomeNiceDisplayName" }
AuthCookie
:
也稱為安全資料,是web服務返回的JSON物件,但由於它將嵌入到接收到的加密令牌中,因此無法從客戶端存取。
它可以稍後透過Webhook或WebRPC HTTP請求來發送。
僅當ResultCode
值為1時,才應返回它。
示例:{ "ResultCode": 1, "UserId": "SomeUniqueStringId", "AuthCookie": { "SecretKey": "SecretValue", "Check": true, "AnotherKey": 1000 } }
Data
:JSON物件,包含應返回給客戶端的任何額外值。
請記住,不支援巢狀陣列或物件。
僅當ResultCode
值為0或1時,才應返回它。
示例:{ "ResultCode": 0, "Data": { "S": "Vpqmazljnbr=", "A": [ 1, -5, 9 ] } }
ResultCode
是唯一必需的返回變數,其他任何變數都是可選的。
下表總結了web伺服器可能返回的內容。
ResultCode | 說明 | UserId | 暱稱 | AuthCookie | 資料 |
---|---|---|---|---|---|
0 | 身份驗證未完成,只傳回資料。* | ||||
1 | 身份驗證成功。 | (可選) | (可選) | (可選) | (可選) |
2 | 身份驗證失敗。錯誤憑證。 | ||||
3 | 無效參數。 |
*:例如這可能有助於實作OAuth 2.0或兩步驗證。
從客戶端讀取資料
以下是如何從回應中獲取返回值的程式碼片段:
在與自訂伺服器進行身份驗證期間返回的用於擷取自訂可選Data
的回調:
C#
void OnCustomAuthenticationResponse(Dictionary<string, object> data)
{
// here you can access the returned data
}
Data Types Conversion
In this section, only the type of data exchanged between Photon server and the web service is explained.
For more information about data types between clients and Photon servers please refer to serialization in Photon page.
Photon Server -> Web Service
C# / .NET (Photon supported types) | JavaScript / JSON |
---|---|
byte
|
number |
short
|
|
int
|
|
long
|
|
double | |
bool
|
bool |
string
|
string |
byte[] (byte array 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
|
Sample request data (types are concatenated)
As sent from Photon Server:<!--
JSON
{
"(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":[
"(Int32)0",
"(String)xy",
"(Boolean)False"
],
"hk_null":"null"
},
"null":"null",
"(String[])string[]":[
"PUN",
"TB",
"RT",
"Bolt",
"Chat"
],
"(Byte[])byte[]":[
"255",
"0"
],
"(Int16[])short[]":[
"-32768",
"32767"
],
"(Int32[])int[]":[
"-2147483648",
"2147483647"
],
"(Int64[])long[]":[
"-9223372036854775808",
"9223372036854775807"
],
"(Single[])float[]":[
"-3.402823E+38",
"3.402823E+38"
],
"(Double[])double[]":[
"-1.79769313486232E+308",
"1.79769313486232E+308"
],
"(Boolean[])bool[]":[
"True",
"False"
]
}
As read by Web Service:
JSON
{
"(object)Dictionary":{
"dk_int":"(number)1",
"dk_str":"(string)dv2",
"dk_bool":"(boolean)true"
},
"(object)Hashtable":{
"(number)hk_byte":"255",
"(array)hk_array":[
"(number)0",
"(string)xy",
"(boolean)false"
],
"hk_null":null
},
"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"
]
}
Web Service -> Photon Server
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
|
Sample response data (types are concatenated)
As sent from Web Service:<!--
JSON
{
"(object)number": {
"(number)MAX_VALUE": "1.7976931348623157e+308",
"(number)MIN_VALUE": "5e-324"
},
"(object)object": {
"(string)string": "xyz",
"null": null,
"(boolean)bool": "false",
"(undefined)undefined": "undefined",
"(number)float": "-3.14",
"(number)integer": "123456"
},
"(array)array": [
"(string)xyz",
"(number)0",
"(boolean)true",
null,
"(undefined)undefined"
]
}
As read from Photon Server:<!--
JSON
{
"(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)float":"-3.14",
"(Int64)integer":"123456"
},
"(Object[])array":[
"(String)xyz",
"(Int64)0",
"(Boolean)True",
"null",
"null"
]
}
故障排除
當自訂身份驗證失敗時,會觸發以下回調:
C#
void OnCustomAuthenticationFailed(string debugMessage)
{
// The `debugMessage` could be what the authentication provider returned.
}
如果您在儀表板中設置的身份驗證URL返回一些HTTP錯誤,Photon伺服器會暫停身份驗證調用一段時間,以避免一些開銷。
在設置或測試URL時,請考慮此「回退」時間。
最佳做法
- 身份驗證提供者返回的結果應包含可讀的
Message
,特別是在失敗的情況下。
這將為您節省大量偵錯的麻煩。 - 在儀表板上,設定不應從客戶端側設定的靜態鍵/值對。
這將防止生成的査詢字串中出現重複鍵。 - 出於安全原因,不要將純文字密碼作為身份驗證參數發送。
- 建議從Photon儀表板設定査詢字串參數。
這樣您就可以檢查請求的來源。 - 使用
AuthenticationValues
方法設定參數,不要直接影響AuthGetParameters
的值。
這將防止査詢字串格式錯誤。
用例示例:封鎖舊客戶端版本
您可以使用自訂身份驗證來拒絕來自使用舊版本(或意外版本)的客戶端的連接,並返回特定錯誤,以便您可以要求用戶進行更新。
為此,您需要在自訂身份驗證請求中發送版本。由您決定是將其作為査詢字串參數還是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." }
。