After I heard about Firebase, I decided it was a good idea to try it on my little Unity game.
I readed the documentation, followed the "Get Started" configuration tutorials, and changed the authentication rules so everyone could insert data.
void Start()
{
// Set up the Editor before calling into the realtime database.
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("https://magicast-bd2fc.firebaseio.com/");
Firebase.Auth.FirebaseAuth.DefaultInstance.StateChanged += DefaultInstance_StateChanged;
// Get the root reference location of the database.
DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
var u = new User();
u.email = "sdjkdsdksadjsad";
u.fb_id = "sakdsajdhasd";
u.username = "jadhsjahjsda";
reference.SetValueAsync(u);
}
This code does execute, but when I go to my Firebase Console, I see no data on the Database tab. I can't figure out what I am doing wrong, and the code gives no errors at all! What am I doing wrong?
This is my user class. It's basically a testing class, no big stuff:
public class User
{
public string username;
public string email;
public string fb_id;
public User()
{
}
public User(string username, string email, string fb_id)
{
this.username = username;
this.email = email;
this.fb_id = fb_id;
}
}
You can't call .set() on arbitrary objects to the Firebase Database, they must come under one of the following categories:
string
long
double
bool
Dictionary<string, Object>
List<Object>
Instead of
reference.SetValueAsync(u);
You need to call
string json = JsonUtility.ToJson(u);
reference.SetRawJsonValueAsync(json);
You are also not actually logging in any user. To log in an anonymous user, first go to the Firebase Console -> Authentication and turn on the 'Anonymous' switch. Then authenticate with the following code:
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
auth.SignInAnonymouslyAsync().ContinueWith(task => {
if (task.IsCanceled) {
Debug.LogError("SignInAnonymouslyAsync was canceled.");
return;
}
if (task.IsFaulted) {
Debug.LogError("SignInAnonymouslyAsync encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})",
newUser.DisplayName, newUser.UserId);
});
You are not authenticated and the default Firebase security rules require that auth != null.
See the docs for how to authenticate with Unity.
Related
For context, this is FireStore using Unity SDK on C#
I've got 2 databases, one public that anyone can read and one private for authenticated users. They both work perfectly fine independently or together if user is authenticated before making a call to the publicly accessible database.
The issue is, if a user makes a call to public database and later on signs in, the calls to the private database come back with insufficient permissions exception.
I feel like original unauthenticated credentials persist somewhere and are being used instead of authenticated user, but could not find a way of disposing of them. Or I may have just missed something super obvious, but this has been plaguing me for far too long.
The following are the rules
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /Public/{document}{
allow read: if resource != null;
allow write: if false;
}
match /User/{userId}{
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
And the following are the relevant call parts that in this order would create an issue I'm describing, this is heavily trimmed of value handling, but yields same result.
Call to public
CollectionReference dailyLevelsRef = db.Collection("Public");
DocumentReference docRef = dailyLevelsRef.Document(docID);
docRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
DocumentSnapshot snapshot = task.Result;
});
Authorization call
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Firebase.Auth.Credential credential =
Firebase.Auth.EmailAuthProvider.GetCredential("email#email.email", "password");
auth.SignInWithCredentialAsync(credential).ContinueWithOnMainThread(task => {
Firebase.Auth.FirebaseUser newUser = task.Result;
m_playerFireBaseID = newUser.UserId;
});
Call to Private
CollectionReference saveDataRef = db.Collection("User");
DocumentReference docRef = saveDataRef.Document(m_playerFireBaseID);
docRef.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
DocumentSnapshot snapshot = task.Result;
});
Does anyone know if it is possible and how to use firebase auth to give additional information, like the name of the User?
I created this method but it only stores emails and passwords.
public void create()
{
FirebaseAuth.DefaultInstance.CreateUserWithEmailAndPasswordAsync(emailInput.text, passwordInput.text).ContinueWith((task => {
if (task.IsCanceled)
{
Firebase.FirebaseException e = task.Exception.Flatten().InnerExceptions[0] as Firebase.FirebaseException;
GetErrorMessage((AuthError)e.ErrorCode);
return;
}
if (task.IsFaulted)
{
Firebase.FirebaseException e = task.Exception.Flatten().InnerExceptions[0] as Firebase.FirebaseException;
GetErrorMessage((AuthError)e.ErrorCode);
return;
}
if (task.IsCompleted)
{
print("Created user");
return;
}
}));
}
I'm new in unity and I started using firebase for about one week.
Sorry, if I asked something obvious, but I searched for days and the documentation is scarce.
Thanks
Use the FirebaseUser.UpdateUserProfileAsync
public void SetPlayerNameAndImage(string playerName, string imageUrl)
{
Firebase.Auth.FirebaseUser user = Firebase.Auth.FirebaseAuth.DefaultInstance.CurrentUser;
if (user != null)
{
Firebase.Auth.UserProfile profile = new Firebase.Auth.UserProfile
{
DisplayName = playerName,
PhotoUrl = new System.Uri(imageUrl),
};
user.UpdateUserProfileAsync(profile).ContinueWith(task => {
if (task.IsCanceled)
{
Debug.LogError("UpdateUserProfileAsync was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("UpdateUserProfileAsync encountered an error: " + task.Exception);
return;
}
Debug.Log("User profile updated successfully.");
});
}
}
Firebase Authentication only has the ability to store per user in the dedicated fields for the user profile and custom claims. The blob of data for custom claims is limited to 1000 bytes of JSON, and it can only be written with a backend SDK, not the Unity client SDK. While you certainly can store data about the user in custom claims, that's not what it's intended to be used for (it's meant for granted access using backend security mechanisms).
What you should do instead is use a database, such as Realtime Database or Firestore to store per-user information, keyed by the Firbase Auth UID, and protect that with security rules so that each user can only access the data that you would like them to access.
I'm really stuck in this for days. I'm using LinqToTwitter with ASP.Net C#
I'm trying to get the new DirectMessages work, I followed the examples but with no luck.
I want the function to work on Button click, so what I tried is:
BtnClick:
`
protected void Btn1_Click(object sender, EventArgs e)
{
string x = MyTest().Result;
}
`
MyTest:
`
static async Task<string> mytest()
{
AspNetAuthorizer auth = DoAuthorization();
var twitterCtx = new TwitterContext(auth);
List<DMEvent> AllDmEvents = new List<DMEvent>();
string Cursor;
DirectMessageEvents dmResponse =
await
(from dm in twitterCtx.DirectMessageEvents
where dm.Type == DirectMessageEventsType.List &&
dm.Count == 10
select dm)
.SingleOrDefaultAsync(); //In debugging mode, after this line is executed, it will go away and keep loading forever and never come back
AllDmEvents.AddRange(dmResponse.Value.DMEvents);
Cursor = dmResponse.Value.NextCursor;
string xxx = (JsonConvert.SerializeObject(AllDmEvents, Formatting.None));
return xxx;
}
`
DoAuthorization:
`
static AspNetAuthorizer DoAuthorization()
{
AspNetAuthorizer auth = new AspNetAuthorizer();
auth = new AspNetAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = "MyConsumerKey",
ConsumerSecret = "MyConsumerSecret ",
OAuthToken = "MyOAuthToken ",
OAuthTokenSecret = "MyOAuthTokenSecret ",
ScreenName = "MyUserName",
UserID = 12345678
}
};
return auth;
}`
Any help would be SO much appreciated!
The DoAuthorization() in your code looks like it came from the Console sample and that won't work with ASP.NET. The reason is that ASP.NET is stateless and the OAuth process brings you to the Twitter site and back. So, you have to break up the authorization into two pieces: Begin and Complete.
I'm guessing that you're using ASP.NET MVC, but the concept is similar (but different) if you're using WebForms). Here's the Begin part:
public class OAuthController : AsyncController
{
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> BeginAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
}
};
Notice that it uses an MvcAuthorizer, populating credentials. Once you have the MvcAuthorizer instance, redirect the user to Twitter for authorization, like this:
string twitterCallbackUrl = Request.Url.ToString().Replace("Begin", "Complete");
return await auth.BeginAuthorizationAsync(new Uri(twitterCallbackUrl));
}
That send the user to the Twitter authorization page, where they give your app permission to operate on their behalf. Twitter will redirect the user back to twitterCallback, which is why the code above modified the URL to replace the Begin with Complete in your URL. So, Twitter redirect the user back to your app, which calls the CompleteAsync() action below:
public async Task<ActionResult> CompleteAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
await auth.CompleteAuthorizeAsync(Request.Url);
// This is how you access credentials after authorization.
// The oauthToken and oauthTokenSecret do not expire.
// You can use the userID to associate the credentials with the user.
// You can save credentials any way you want - database,
// isolated storage, etc. - it's up to you.
// You can retrieve and load all 4 credentials on subsequent
// queries to avoid the need to re-authorize.
// When you've loaded all 4 credentials, LINQ to Twitter will let
// you make queries without re-authorizing.
//
//var credentials = auth.CredentialStore;
//string oauthToken = credentials.OAuthToken;
//string oauthTokenSecret = credentials.OAuthTokenSecret;
//string screenName = credentials.ScreenName;
//ulong userID = credentials.UserID;
//
return RedirectToAction("Index", "Home");
}
Now that your app has the user's permissions, grab their tokens and hold them for subsequent queries so you don't have to continue the OAuth process every time the user wants to use your app. Please see the notes in the code on how to get those credentials.
Now, when you want to perform a query, instantiate an MvcAuthorizer, like this:
static async Task<string> mytest()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
var twitterCtx = new TwitterContext(auth);
List<DMEvent> AllDmEvents = new List<DMEvent>();
string Cursor;
DirectMessageEvents dmResponse =
await
(from dm in twitterCtx.DirectMessageEvents
where dm.Type == DirectMessageEventsType.List &&
dm.Count == 10
select dm)
.SingleOrDefaultAsync(); //In debugging mode, after this line is executed, it will go away and keep loading forever and never come back
AllDmEvents.AddRange(dmResponse.Value.DMEvents);
Cursor = dmResponse.Value.NextCursor;
string xxx = (JsonConvert.SerializeObject(AllDmEvents, Formatting.None));
return xxx;
}
You can see how the first statement of your modified myTest() method instantiates MvcAuthorizer with SessionStateCredentialStore, holding your credentials.
Finally, at the point in time where you want the user to authorize your app with Twitter (log in, on first query, or any other timing of your choice), check to see whether they're already authorized and re-direct if not, like this:
public ActionResult Index()
{
if (!new SessionStateCredentialStore().HasAllCredentials())
return RedirectToAction("Index", "OAuth");
return View();
}
Notice how the code above calls HasAllCredentials() on a SessionStateCredentialStore instance. I assume that you'll be adding your own logic to determine when to load the user's credentials, but wanted you to be aware of the HasAllCredentials() helper method to make it easier to know when the user must be authorized.
For more info, visit the LINQ to Twitter OAuth docs. The LINQ to Twitter source code also has Samples on how to use OAuth.
I'm trying to get phone number authentication for Unity up and running but I am getting no SMS response. The documentation online is super unclear about how to do this. I'd much rather have Google Auth for Firebase but apparently it isn't supported yet. Can anyone help me figure out how to get this up and running?
Here is what I have so far...
public class SignIn : MonoBehaviour {
private string phoneNumber;
private string secureCode;
private uint phoneAuthTimeoutMs;
private Firebase.Auth.FirebaseAuth firebaseAuth;
private Credential credential;
private string verificationId;
private string verificationCode;
public Text PhoneNumberInputFieldText;
public Text SecureCodeInputFieldText;
public Button SendSecureCodeButton;
public Button SubmitSecureCodeButton;
// Use this for initialization
void Start()
{
SendSecureCodeButton.GetComponent<Button>().onClick.AddListener(() => StartSignIn());
}
// Update is called once per frame
void Update () {
}
void StartSignIn()
{
firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
phoneAuthTimeoutMs = 60000;
phoneNumber = PhoneNumberInputFieldText.text;
Debug.Log(phoneNumber);
if (PlayerPrefs.GetString("secureCode") != null)
{
verificationId = PlayerPrefs.GetString("secureCode");
}
PhoneAuthProvider provider = PhoneAuthProvider.GetInstance(firebaseAuth);
provider.VerifyPhoneNumber(phoneNumber, phoneAuthTimeoutMs, null,
verificationCompleted: (credential) =>
{
// Auto-sms-retrieval or instant validation has succeeded (Android only).
// There is no need to input the verification code.
// `credential` can be used instead of calling GetCredential().
},
verificationFailed: (error) =>
{
// The verification code was not sent.
// `error` contains a human readable explanation of the problem.
},
codeSent: (id, token) =>
{
//Prompt here to type in SecureCode
PlayerPrefs.SetString("secureCode", id);
credential = provider.GetCredential(verificationId, verificationCode);
firebaseAuth.SignInWithCredentialAsync(credential).ContinueWith(task => {
if (task.IsFaulted)
{
Debug.LogError("SignInWithCredentialAsync encountered an error: " +
task.Exception);
return;
}
FirebaseUser newUser = task.Result;
Debug.Log("User signed in successfully");
// This should display the phone number.
Debug.Log("Phone number: " + newUser.PhoneNumber);
// The phone number providerID is 'phone'.
Debug.Log("Phone provider ID: " + newUser.ProviderId);
});
// Verification code was successfully sent via SMS.
// `id` contains the verification id that will need to passed in with
// the code from the user when calling GetCredential().
// `token` can be used if the user requests the code be sent again, to
// tie the two requests together.
},
codeAutoRetrievalTimeOut: (id) =>
{
// Called when the auto-sms-retrieval has timed out, based on the given
// timeout parameter.
// `id` contains the verification id of the request that timed out.
});
}
}
Thanks in advance!
Here is my Firebase Console:
I'll post an answer but i'll edit this.
Try a simplier sending SMS phone verification
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
phoneNumber = "your phone number here";//state the phone number here first
uint phoneAuthTimeoutMs = 10000;
PhoneAuthProvider provider = PhoneAuthProvider.GetInstance(auth);
provider.VerifyPhoneNumber(phoneNumber, phoneAuthTimeoutMs,null,
verificationCompleted: (credential) => {
},
verificationFailed: (error) => {
},
codeSent: (id, token) => {
MyText.text = "SMS Has been sent " + id;
},
codeAutoRetrievalTimeOut : (id) => {
});
MyText.text += "HMM";
Then please tell me if it works. Now if it works we will proceed to the next step
I am trying to build a registration section for a website (internal to my dept). Now to get new users registered, I built a form where user enters his employee id i.e. AD account name and then clicks a button to fetch his details. Which are later saved in database where registration requests are queued. Once those requests are approved by admin then only those users can use the application. Now the problem is that user is not logged in, so is it possible for non logged in user to fetch details from AD server. if it is then how.? Because when I tried the below listed code I am getting bad username or password error using FindOne function.
public string getProperties(string StaffCode, string property)
{
try
{
string result = "";
using (var de = new DirectoryEntry(_path))
using (var ds = new DirectorySearcher(de))
{
ds.Filter = string.Format("(sAMAccountName={0})", StaffCode);
ds.PropertiesToLoad.AddRange(new[] {
"sn", // last name
"givenName", // first name
"mail", // email
"telephoneNumber", // phone number
// etc - add other properties you need
});
var res = ds.FindOne();
if (res == null)
{
result = "noUserFound";
}
else
{
foreach (string propName in res.Properties.PropertyNames)
{
ResultPropertyValueCollection valueCollection = res.Properties[propName];
foreach (Object propertyValue in valueCollection)
{
if (propName == property)
{
result = propertyValue.ToString();
}
}
}
}
}
return result;
}
catch (Exception ex)
{
return "someErrorOccurred";
}
Please help me in overcoming this issue.
Thanks in advance
My guess is that the identity of the application pool you run this code under doesn't have enough priviledges to query the AD without authentication.
Specifically, start with replacing this constructor
using ( var de = new DirectoryEntry( _path ) )
with the one that takes admin's username/password in an explicit way
using ( var de = new DirectoryEntry( _path, username, password ) )
and make sure the username has enough priviledges to query the catalog.
If this works, you could possibly try to go back to the original version but you'd have to make sure the identity of the asp.net application pool has enough priviledges to query the AD but also, that the asp.net server is a part of the domain (if it is not, authentication without providing username/password in an explicit way will most likely not work).