Skip to content

Commit eb755b9

Browse files
committed
✨ Anonymous SignIn && handle token refresh
1 parent 06540f3 commit eb755b9

File tree

3 files changed

+123
-82
lines changed

3 files changed

+123
-82
lines changed

Assets/FirebaseREST/Auth/FirebaseAuth.cs

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public class FirebaseAuth : MonoBehaviour
1212
{
1313
readonly string EMAIL_AUTH_URL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=" + FirebaseSettings.WEB_API;
1414
readonly string CUSTOM_TOKEN_AUTH_URL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=" + FirebaseSettings.WEB_API;
15+
readonly string ANONYMOUS_AUTH_URL = "https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + FirebaseSettings.WEB_API;
1516
readonly string REFRESH_TOKEN_URL = "https://securetoken.googleapis.com/v1/token?key=" + FirebaseSettings.WEB_API;
1617
readonly string USER_INFO_URL = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=" + FirebaseSettings.WEB_API;
1718
TokenData tokenData;
@@ -64,36 +65,27 @@ void OnDestroy()
6465
{
6566
applicationIsQuitting = true;
6667
}
68+
69+
public bool IsSignedIn => tokenData != null;
6770

68-
public string AccessToken
69-
{
70-
get
71-
{
72-
if (tokenData == null)
73-
return null;
74-
return tokenData.idToken;
75-
}
76-
}
77-
78-
public bool IsSignedIn
79-
{
80-
get
81-
{
82-
return tokenData != null;
83-
}
71+
public void GetAccessToken(Action<string> onComplete) {
72+
if (tokenData == null)
73+
onComplete?.Invoke(null);
74+
else if (IsTokenExpired)
75+
RefreshAccessToken(10, response => onComplete(response.data.IdToken));
76+
else
77+
onComplete?.Invoke(tokenData.IdToken);
8478
}
8579

86-
void Awake()
87-
{
80+
private bool IsTokenExpired => DateTime.Now - tokenData.RefreshedAt > TimeSpan.FromSeconds(double.Parse(tokenData.ExpiresIn));
8881

89-
}
9082

9183
public void FetchUserInfo(int timeout, Action<Response<List<UserData>>> OnComplete)
9284
{
9385
if (tokenData == null)
9486
throw new Exception("User has not logged in");
9587
UnityWebRequestAsyncOperation op = StartRequest(USER_INFO_URL, "POST", new Dictionary<string, object>(){
96-
{"idToken",tokenData.idToken}
88+
{"idToken",tokenData.IdToken}
9789
}, timeout);
9890
op.completed += ((ao) => HandleFirebaseResponse(op, (res) =>
9991
{
@@ -148,17 +140,15 @@ public void RefreshAccessToken(int timeout, Action<Response<TokenData>> OnComple
148140
if (tokenData == null)
149141
throw new Exception("User has not logged in");
150142
UnityWebRequestAsyncOperation op = StartRequest(REFRESH_TOKEN_URL, "POST", new Dictionary<string, object>(){
151-
{"grant_type","refresh_token"},{"refresh_token",tokenData.refreshToken}
143+
{"grant_type","refresh_token"},{"refresh_token",tokenData.RefreshToken}
152144
}, timeout);
153145
op.completed += ((ao) => HandleFirebaseResponse(op, (res) =>
154146
{
155147
if (res.success)
156148
{
157149
Dictionary<string, object> dataMap = Json.Deserialize(op.webRequest.downloadHandler.text) as Dictionary<string, object>;
158-
this.tokenData = new TokenData();
159-
tokenData.expiresIn = dataMap["expires_in"].ToString();
160-
tokenData.idToken = dataMap["id_token"].ToString();
161-
tokenData.refreshToken = dataMap["refresh_token"].ToString();
150+
tokenData = new TokenData(dataMap["id_token"].ToString(), dataMap["refresh_token"].ToString(),
151+
dataMap["expires_in"].ToString(), DateTime.Now);
162152
if (OnComplete != null)
163153
OnComplete(new Response<TokenData>("success", true, (int)op.webRequest.responseCode, tokenData));
164154
}
@@ -185,6 +175,14 @@ public void SignInWithEmail(string email, string password, int timeout, Action<R
185175
}, timeout);
186176
op.completed += ((ao) => HandleFirebaseSignInResponse(op, OnComplete));
187177
}
178+
179+
public void SignInAnonymously(int timeout, Action<Response<TokenData>> OnComplete)
180+
{
181+
UnityWebRequestAsyncOperation op = StartRequest(ANONYMOUS_AUTH_URL, "POST", new Dictionary<string, object>(){
182+
{"returnSecureToken",true}
183+
}, timeout);
184+
op.completed += ((ao) => HandleFirebaseSignInResponse(op, OnComplete));
185+
}
188186

189187
UnityWebRequestAsyncOperation StartRequest(string url, string requestMethod, Dictionary<string, object> data, int timeout)
190188
{
@@ -216,10 +214,7 @@ void HandleFirebaseSignInResponse(UnityWebRequestAsyncOperation webReqOp, Action
216214
if (OnComplete != null)
217215
{
218216
Dictionary<string, object> dataMap = Json.Deserialize(webReqOp.webRequest.downloadHandler.text) as Dictionary<string, object>;
219-
this.tokenData = new TokenData();
220-
tokenData.expiresIn = dataMap["expiresIn"].ToString();
221-
tokenData.idToken = dataMap["idToken"].ToString();
222-
tokenData.refreshToken = dataMap["refreshToken"].ToString();
217+
this.tokenData = new TokenData(dataMap["idToken"].ToString(), dataMap["refreshToken"].ToString(), dataMap["expiresIn"].ToString(), DateTime.Now);
223218
OnComplete(new Response<TokenData>("success", true, (int)webReqOp.webRequest.responseCode, tokenData));
224219
}
225220
}
Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1+
using System;
2+
13
namespace FirebaseREST
24
{
35
public class TokenData
46
{
5-
public string idToken;
6-
public string refreshToken;
7-
public string expiresIn;
7+
public string IdToken { get; }
8+
public string RefreshToken { get; }
9+
public string ExpiresIn { get; }
10+
public DateTime RefreshedAt { get; }
11+
12+
public TokenData(string idToken, string refreshToken, string expiresIn, DateTime refreshedAt) {
13+
IdToken = idToken;
14+
RefreshToken = refreshToken;
15+
ExpiresIn = expiresIn;
16+
RefreshedAt = refreshedAt;
17+
}
818
}
919
}

Assets/FirebaseREST/Database/DatabaseReference.cs

Lines changed: 86 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -52,28 +52,35 @@ void BeginListeningServerEvents()
5252
#if UNITY_WEBGL && !UNITY_EDITOR
5353
if (esGL != null) return;
5454
string url = this.ReferenceUrl;
55-
bool withCredential = false;
56-
if (FirebaseAuth.Instance.IsSignedIn)
57-
{
58-
url = url + "?auth=" + FirebaseAuth.Instance.AccessToken;
59-
withCredential = true;
55+
if (FirebaseAuth.Instance.IsSignedIn) {
56+
FirebaseAuth.Instance.GetAccessToken((accessToken) => {
57+
url = url + "?auth=" + accessToken;
58+
esGL = new FirebaseDatabase.FirebaseEventSourceWebGL(url, true, null,
59+
OnEventSourceMessageReceived, OnEventSourceError);
60+
});
61+
}
62+
else {
63+
esGL = new FirebaseDatabase.FirebaseEventSourceWebGL(url, false, null,
64+
OnEventSourceMessageReceived, OnEventSourceError);
6065
}
61-
esGL = new FirebaseDatabase.FirebaseEventSourceWebGL(url, withCredential, null,
62-
OnEventSourceMessageReceived, OnEventSourceError);
66+
6367
#else
6468
if (webReq != null) return;
6569
string url = this.ReferenceUrl;
66-
if (FirebaseAuth.Instance.IsSignedIn)
67-
url = url + "?auth=" + FirebaseAuth.Instance.AccessToken;
68-
webReq = new UnityWebRequest(url);
69-
webReq.SetRequestHeader("Accept", "text/event-stream");
70-
webReq.SetRequestHeader("Cache-Control", "no-cache");
71-
FirebaseServerEventsDownloadHandler downloadHandler = new FirebaseServerEventsDownloadHandler();
72-
downloadHandler.DataReceived += OnDataReceived;
73-
webReq.downloadHandler = downloadHandler;
74-
webReq.disposeDownloadHandlerOnDispose = true;
75-
UnityWebRequestAsyncOperation webReqAO = webReq.SendWebRequest();
76-
webReqAO.completed += ((ao) => OnStopListening(webReqAO));
70+
if (FirebaseAuth.Instance.IsSignedIn) {
71+
FirebaseAuth.Instance.GetAccessToken(accessToken => {
72+
url = url + "?auth=" + accessToken;
73+
webReq = new UnityWebRequest(url);
74+
webReq.SetRequestHeader("Accept", "text/event-stream");
75+
webReq.SetRequestHeader("Cache-Control", "no-cache");
76+
FirebaseServerEventsDownloadHandler downloadHandler = new FirebaseServerEventsDownloadHandler();
77+
downloadHandler.DataReceived += OnDataReceived;
78+
webReq.downloadHandler = downloadHandler;
79+
webReq.disposeDownloadHandlerOnDispose = true;
80+
UnityWebRequestAsyncOperation webReqAO = webReq.SendWebRequest();
81+
webReqAO.completed += ((ao) => OnStopListening(webReqAO));
82+
});
83+
}
7784
#endif
7885
}
7986

@@ -498,17 +505,22 @@ public override void GetValueAsync(int timeout, Action<Response<DataSnapshot>> O
498505
webReq.downloadHandler = new DownloadHandlerBuffer();
499506
webReq.timeout = timeout;
500507

501-
if (FirebaseAuth.Instance.IsSignedIn)
502-
{
503-
string sign = query == null ? "?" : "&";
504-
webReq.url = webReq.url + sign + "auth=" + FirebaseAuth.Instance.AccessToken;
508+
Action sendRequest = () => {
509+
var op = webReq.SendWebRequest();
510+
op.completed += (ao) => HandleFirebaseDatabaseResponse(op, res => {
511+
OnComplete?.Invoke(new Response<DataSnapshot>(res.message, res.success, res.code, new FirebaseDataSnapshot(this, Json.Deserialize(res.data))));
512+
});
513+
};
514+
515+
if (FirebaseAuth.Instance.IsSignedIn) {
516+
FirebaseAuth.Instance.GetAccessToken(accessToken => {
517+
string sign = query == null ? "?" : "&";
518+
webReq.url = webReq.url + sign + "auth=" + accessToken;
519+
sendRequest();
520+
});
521+
} else {
522+
sendRequest();
505523
}
506-
UnityWebRequestAsyncOperation op = webReq.SendWebRequest();
507-
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, (res) =>
508-
{
509-
if (OnComplete != null)
510-
OnComplete(new Response<DataSnapshot>(res.message, res.success, res.code, new FirebaseDataSnapshot(this, Json.Deserialize(res.data))));
511-
}));
512524
}
513525

514526
public void Push(object data, int timeout, Action<Response<string>> OnComplete)
@@ -558,10 +570,19 @@ public void RemoveValueAsync(int timeout, Action<Response> OnComplete)
558570
webReq.SetRequestHeader("Content-Type", "application/json");
559571
webReq.timeout = timeout;
560572

561-
if (FirebaseAuth.Instance.IsSignedIn)
562-
webReq.url = webReq.url + "?auth=" + FirebaseAuth.Instance.AccessToken;
563-
UnityWebRequestAsyncOperation op = webReq.SendWebRequest();
564-
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, OnComplete));
573+
Action sendRequest = () => {
574+
var op = webReq.SendWebRequest();
575+
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, OnComplete));
576+
};
577+
578+
if (FirebaseAuth.Instance.IsSignedIn) {
579+
FirebaseAuth.Instance.GetAccessToken((accessToken) => {
580+
webReq.url = webReq.url + "?auth=" + accessToken;
581+
sendRequest();
582+
});
583+
} else {
584+
sendRequest();
585+
}
565586
}
566587

567588
void PushFirebaseData(string dbpath, string rawData, int timeout, Action<Response<string>> OnComplete)
@@ -573,20 +594,26 @@ void PushFirebaseData(string dbpath, string rawData, int timeout, Action<Respons
573594
webReq.SetRequestHeader("Content-Type", "application/json");
574595
webReq.timeout = timeout;
575596

576-
if (FirebaseAuth.Instance.IsSignedIn)
577-
webReq.url = webReq.url + "?auth=" + FirebaseAuth.Instance.AccessToken;
578-
UnityWebRequestAsyncOperation op = webReq.SendWebRequest();
579-
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, (res) =>
580-
{
581-
string pushedId = null;
582-
if (res.success)
583-
{
584-
Dictionary<string, object> data = Json.Deserialize(res.data) as Dictionary<string, object>;
585-
pushedId = data["name"].ToString();
586-
}
587-
if (OnComplete != null)
588-
OnComplete(new Response<string>(res.message, res.success, res.code, pushedId));
589-
}));
597+
Action sendRequest = () => {
598+
var op = webReq.SendWebRequest();
599+
op.completed += (ao) => HandleFirebaseDatabaseResponse(op, (res) => {
600+
string pushedId = null;
601+
if (res.success) {
602+
Dictionary<string, object> data = Json.Deserialize(res.data) as Dictionary<string, object>;
603+
pushedId = data["name"].ToString();
604+
}
605+
OnComplete?.Invoke(new Response<string>(res.message, res.success, res.code, pushedId));
606+
});
607+
};
608+
609+
if (FirebaseAuth.Instance.IsSignedIn) {
610+
FirebaseAuth.Instance.GetAccessToken(accessToken => {
611+
webReq.url = webReq.url + "?auth=" + accessToken;
612+
sendRequest();
613+
});
614+
} else {
615+
sendRequest();
616+
}
590617
}
591618

592619
void WriteFirebaseData(string dbpath, object data, int timeout, string requestMethod, Action<Response> OnComplete)
@@ -598,10 +625,19 @@ void WriteFirebaseData(string dbpath, object data, int timeout, string requestMe
598625
webReq.SetRequestHeader("Content-Type", "application/json");
599626
webReq.timeout = timeout;
600627

601-
if (FirebaseAuth.Instance.IsSignedIn)
602-
webReq.url = webReq.url + "?auth=" + FirebaseAuth.Instance.AccessToken;
603-
UnityWebRequestAsyncOperation op = webReq.SendWebRequest();
604-
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, OnComplete));
628+
Action sendRequest = () => {
629+
var op = webReq.SendWebRequest();
630+
op.completed += ((ao) => HandleFirebaseDatabaseResponse(op, OnComplete));
631+
};
632+
633+
if (FirebaseAuth.Instance.IsSignedIn) {
634+
FirebaseAuth.Instance.GetAccessToken((accessToken) => {
635+
webReq.url = webReq.url + "?auth=" + accessToken;
636+
sendRequest();
637+
});
638+
} else {
639+
sendRequest();
640+
}
605641
}
606642

607643
void HandleFirebaseDatabaseResponse(UnityWebRequestAsyncOperation webReqOp, Action<Response> OnComplete)

0 commit comments

Comments
 (0)