I am working on building out an authentication system for a project I am working on.
Part of this is to save UserData locally so that it doesn't have to connect to cloud on every run, or force a login ETC.
The problem i am having, is when i am trying to set PlayerPrefs it is not working. I have it running a Debug.Log before each PlayerPrefs.SetString and it only ever displays the first one.
I am able to do PlayerPrefs.SetString in my Start() but for some reason it is not working here and i have no idea why.
Everything works up until i am saving to PlayerPrefs
public Dictionary<string, string> LoggedUser = new Dictionary<string, string>();
public void getUserData(string id, string email)
{
Debug.Log("Getting User Data for ID: " + id);
FirebaseDatabase.DefaultInstance
.GetReference(id)
.GetValueAsync().ContinueWith(task1 =>
{
if (task1.IsFaulted)
{
Debug.Log("Failed");
}
else if (task1.IsCompleted)
{
Debug.Log("Data Retrieved");
DataSnapshot snapshot = task1.Result;
foreach (DataSnapshot user in snapshot.Children)
{
string firstName = user.Child("firstName").Value.ToString();
string lastName = user.Child("lastName").Value.ToString();
string sex = user.Child("sex").Value.ToString();
string country = user.Child("country").Value.ToString();
string age = user.Child("age").Value.ToString();
string userName = user.Child("userName").Value.ToString();
Debug.Log(firstName);
LoggedUser.Add("FirstName", firstName);
LoggedUser.Add("LastName", lastName);
LoggedUser.Add("Email", email);
LoggedUser.Add("age", age);
LoggedUser.Add("sex", sex);
LoggedUser.Add("country", country);
LoggedUser.Add("userName", userName);
Debug.Log("Welcome " + LoggedUser["FirstName"]);
Debug.Log("User signed in successfully: " +newUser.Email +" " +newUser.UserId);
setPlayer();
}
}
});
}
public void setPlayer()
{
Debug.Log("Saving to PlayerPrefs");
Debug.Log("Setting First Name");
PlayerPrefs.SetString("FirstName", "Ezekiel");
Debug.Log("Setting Last Name");
PlayerPrefs.SetString("LastName", LoggedUser["LastName"]);
Debug.Log("Setting Email");
PlayerPrefs.SetString("Email", LoggedUser["Email"]);
Debug.Log("Setting Age");
PlayerPrefs.SetString("age", LoggedUser["age"]);
Debug.Log("Setting Sex");
PlayerPrefs.SetString("sex", LoggedUser["sex"]);
Debug.Log("Setting Country");
PlayerPrefs.SetString("country", LoggedUser["country"]);
Debug.Log("Setting userName");
PlayerPrefs.SetString("userName", LoggedUser["username"]);
Debug.Log("Setting Loggedn State");
PlayerPrefs.SetInt("LoggedIn", 1);
Debug.Log("Saving Player Prefs");
PlayerPrefs.Save();
Debug.Log("Welcome " + PlayerPrefs.GetString("username"));
}
If you don't mind, I can expand on your answer a little bit.
If you use ContinueWithOnMainThread instead of ContinueWith, your continuation logic automatically occurs on the main thread (so you can write PlayerPrefs). I cover a whole ton of ways to handle threading with Firebase and Unity in this article if you'd like to compare them.
Furthermore, this is a stab in the dark, but if you're using Realtime Database then you may also be using Firebase Authentication. If this is the case, then FirebaseAuth.DefaultInstance.CurrentUser actually persists between runs of your game (I cover this a little bit in this video). Since Realtime Database also caches data you request locally, you may actually be doing extra work that the Firebase plugins will handle for you!
I was able to find the solution.
getUserData() method is running async, which creats a new thread. the PlayerPrefs can only run on a main thread.
My solution was to create a boolean that i flippd to true when the Data was loaded into LoggedUser. my Update() method was watching for that to flip to true, where it then called the setPlayer().
Than you all for the help!
You are setting userName
PlayerPrefs.SetString("userName", LoggedUser["username"]);
and retrieving username
Debug.Log("Welcome " + PlayerPrefs.GetString("username"));
Also it should be
PlayerPrefs.SetString("userName", LoggedUser["userName"]);
instead of
PlayerPrefs.SetString("userName", LoggedUser["username"]);
Related
I am using Firesharp for my app in c# winforms. This database is also connected to my ReactJS website which deals with the same information.
I have noticed that when I make .SetAsync calls to my app on the website and then log in to my Winforms app, my WinForms app will automatically perform the last action I did on my website to my database which is a .setAsync() action which adds some user information to a list of other user's information. Now it will not stop. Anytime I log on to my c# app, it runs it.
It makes me think there is a queue of orders in firesharp?
here is my react code. From what I can tell, it is nothing out of the ordinary:
async function handleSubmit(e) {
e.preventDefault()
var date = moment().format("MM/DD/YYYY" )
setError("")
setLoading(true)
// grab user info first then use that.
await firebaseApp.database().ref("Users/" + currentUser.uid + "/UserData").on('value', snapshot => {
if (snapshot.val() != null) {
setContactObjects({
...snapshot.val()
})
firebaseApp.database().ref("Projects/" + projectGUIDRef.current.value + "/queueList/" + userIdRef.current.value).set({
"EntryTimeStamp": date + " " + moment().format("hh:mm:ss a"),
"IsSyncing": false,
"UserId": userIdRef.current.value,
"UserName": usernameRef.current.value,
})
}
})
history.push("/Demo")
setLoading(false)
}
here is my c# winforms code of where the code is executing. For some reason, when this executes, it also updates the EntryTimeStamp field of the react code and completely sets all the information even if I delete it. It also happens if I run .set().
updateLastLogin2(authLink);
private async void updateLastLogin2(FirebaseAuthLink authLink)
{
IFirebaseConfig config = new FireSharp.Config.FirebaseConfig
{
AuthSecret = this.authLink.FirebaseToken,
BasePath = Command.dbURL,
};
IFirebaseClient client = new FireSharp.FirebaseClient(config);
string newDateTime = DateTime.Now.ToString();
if (authLink.User.DisplayName.Contains(adUserId) && authLink.User.DisplayName.Contains(adUserId))
{
await client.SetAsync("Users/" + this.authLink.User.LocalId + "/UserData/DateLastLogin", newDateTime);
}
}
Any and all help is appreciated, I've been at this for a day and a half now.
I have never used fire-sharp but this is my guess
You are calling await firebaseApp.database().ref("Users/" + currentUser.uid + "/UserData").on('value' in your react, and then in your Csharp you are calling client.SetAsync("Users/" + this.authLink.User.LocalId .
What happens is the both listeners are listening to each other and then causing a loop.
In that case it's probably better to use once instead of on if you are just using it once.
In cases where you cannot use .once, then you should use .off to turn off the listener once you are done.
firebaseApp.database().ref("Users/" + currentUser.uid + "/UserData").once('value'`
You also shouldn't be using await here since ref().on creates a listener, it doesn't return a promise.
You should also move history.push("/Demo") into your firebase database callback function so it's called after you have set data
How do you grant someone access to select Reporting Services from the drop down within Management Studio as per the below image.
Also, I have a colleague who has full admin access to this however when they run the below with the credentials set to DefaultCredentials we seem still be getting an error:
namespace ReportingServicesJobsUtility
{
public class Program
{
public static void Main(string[] args)
{
ListJobSSRS();
}
public static void ListJobSSRS()
{
//create instance of ReportingService2010 called server
server.ReportingService2010 rs = new server.ReportingService2010();
//user credentials running application to be used
rs.Credentials = CredentialCache.DefaultCredentials;
//rs.Credentials = new System.Net.NetworkCredential("","");
//create array of jobs
Job[] jobs = null;
try
{
jobs = rs.ListJobs();
ListRunningJobs(jobs);
}
catch (SoapException e)
{
Console.WriteLine(e.Detail.InnerXml.ToString());
}
Console.ReadLine();
}
//make this a void?
public static bool ListRunningJobs(server.Job[] jobs)
{
int runningJobCount = 0;
Console.WriteLine("Current Jobs");
Console.WriteLine("================================" + Environment.NewLine);
server.Job job = default(server.Job);
foreach (var j in jobs)
{
Console.WriteLine("--------------------------------");
Console.WriteLine("JobID: {0}", job.JobID);
Console.WriteLine("--------------------------------");
Console.WriteLine("Action: {0}", job.JobActionName);
Console.WriteLine("Description: {0}", job.Description);
Console.WriteLine("Machine: {0}", job.Machine);
Console.WriteLine("Name: {0}", job.Name);
Console.WriteLine("Path: {0}", job.Path);
Console.WriteLine("StartDateTime: {0}", job.StartDateTime);
Console.WriteLine("Status: {0}", job.JobStatusName);
Console.WriteLine("Type: {0}", job.JobTypeName);
Console.WriteLine("User: {0}" + Environment.NewLine, job.User);
runningJobCount += 1;
}
Console.Write("There are {0} running jobs. ", runningJobCount);
//returning a true for no reason
return true;
}
}
}
The error message is as follows and we believe this is down to credentials, unless anyone can also shed some light on this?
edit
If I use rs.Credentials = new System.Net.NetworkCredential(#"developmentserver\Administrator","password"); on our development server then this runs with no problems, so it seems that it does not like using DefualtCredentials, either that or mine and my collegue's AD credentials are not sufficient, so back to the original question how do we grant full access to our logons.
Have you tried adding the accounts you want in the Report Manager and setting the role assignment there?
you are asking for advice on two very different issues and i have some idea for the second one only.
you are not describing the layout of the servers involved so i make the assumption that you are on a client machine accessing a webservice that is a bridge to reach a SSRS instance; webservice and SSRS are not on the same machine.
if this is the case then check if you are running into the double hop issue.
ok, i got it sorted thanks to LordALMMa, but now i have another problem. I want to determine if the user clicks Admin or User radiobutton when registering. I think i should append it to the end of the line on the text file where the name and password is, but how would i do it? Here is the relevant code:
Radio Button Check
public bool radioButtons()
{
string usertypebutton;
if (!userButton.Checked && !adminButton.Checked)
{
MessageBox.Show("You must select an account type");
return false;
}
else
{
if (userButton.Checked)
{
usertypebutton = "User";
}
else
{
usertypebutton = "Admin";
}
return true;
}
}
Streamwriter for registering:
public void mySW()
{
string path = #"C:\Other\myFile.txt";
string userName = userNameBox.Text;
string password = passwordBox.Text;
string usertype = usertypebutton;
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.WriteLine("Username: {0} Password: {1} Type: {3}" , userName, password, usertype);
// No need to close nor dispose your StreamWriter.
// You're inside a using statement for that!
}
MessageBox.Show("Thanks for registering! \n\nYou may now log in!", "Registration SuccessFul");
Application.OpenForms[0].Show();
this.Close();
}
Logging In:
private void logonButton_Click(object sender, EventArgs e)
{
// Loads your users storage
var users = File.ReadAllLines(#"C:\Other\myFile.txt");
// Creates the line with username + password
var usernamePassword = String.Format("Username: {0} Password: {1}", userNameBox.Text, passwordBox.Text);
// Locates the user on your storage
var userFound = users.SingleOrDefault(_u => _u.Equals(usernamePassword));
if (userFound != null)
{
MessageBox.Show("Welcome back, " + userNameBox.Text);
}
else
{
MessageBox.Show("Sorry, you have entered incorrect details\n\nPlease try again");
userNameBox.Text = "";
passwordBox.Text = "";
}
}
So (I think) essentially i want to pass the value usertypebutton from radiobutton method, to the SW. How would i do it, as i'm already passing a boolean value?
Anthony
One part of the problem is that you are not writing the same string that you're reading:
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
I'm guessing that was a typo in your post... but if not that could be your issue.
The other problem is probably this right here:
using (StreamWriter writer = new StreamWriter(path, true))
If you look up the documentation on that overload of the StreamWriter constructor, you'd see that you specified append = true. You are appending each set of login credentials to a file on its own line. But then later, you are only reading the first line of that file. So you will always read the first set of credentials that were entered when the file was first created.
That aside, I hope you are just doing this as an experiment since it is not a secure way of managing passwords to write them to a file like that. Also, you don't need to call Close and Dispose on a Stream if you wrap it in a using block, so you should stick to doing that.
Anthony, dispite the fact that storing logins this way is a major security problem (it's not even a risk anymore), there are some changes to your code that I'd do.
The issue is that you're not storing "Username: [username] Password: [password]".
If you double-check your saving method, you're storing "Password: [username] Password: [password]". That's why they are never found.
Here follows some changes:
Consider:
public void mySW()
{
string path = #"C:\Other\myFile.txt";
string userName = userNameBox.Text;
string password = passwordBox.Text;
using (StreamWriter writer = new StreamWriter(path, true))
{
// This overload makes your life easier by auto-formatting variables for you.
// Also, avoid the "string1 + string2" concatenation mode.
// Use String.Format instead. It's easier to read and keep over time.
writer.WriteLine("Username: {0} Password: {1}", userName, password);
// No need to close nor dispose your StreamWriter.
// You're inside a using statement for that!
}
MessageBox.Show("Thanks for registering! \n\nYou may now log in!", "Registration SuccessFul");
Application.OpenForms[0].Show();
this.Close();
}
And your other method should look like:
{
// Loads your users storage
var users = File.ReadAllLines(#"C:\Other\myFile.txt");
// Creates the line with username + password
var usernamePassword = String.Format("Username: {0} Password: {1}", userNameBox.Text, passwordBox.Text);
// Locates the user on your storage
// This uses Linq syntax with lambda. Linq without lamba looks similar to SQL.
// Lambda is a bit more advanced but reduces code-size and it's easier to understand (IMHO).
// This code will iterate through users (list of string) and try to retrieve one that's equal to the contents of usernamePassword.
var userFound = users.SingleOrDefault(_u => _u.Equals(usernamePassword));
// If null, indicates that no username/password combination was found.
if (userFound != null)
{
MessageBox.Show("Welcome back, " + userNameBox.Text);
}
else
{
MessageBox.Show("Sorry, you have entered incorrect details\n\nPlease try again");
userNameBox.Text = "";
passwordBox.Text = "";
}
}
I'm not checking for the exception. SingleOrDefault will throw an exception if 2 or more records are found mathing the search pattern.
I'm not checking that because this will increase complexity here with try-catch and also because for that to work properly, I'd have to check if they exits BEFORE recording, so changing the register method.
But I think you've got the idea here.
Have you checked your output files? You are writing Password: X Password: Y:
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
and you are checking Username: X Password: Y
if (user == ("Username: "+userNameBox.Text.Trim()+" "+"Password: "+passwordBox.Text.Trim()))
You are adding line as
writer.WriteLine("Password: " + userName + " " + "Password: " + password);
^1 ^2
^1 must be Username:
There are some points which I cannot pass without pointing:
What would you do if file structure corrupted?
What if a user wants to register twice with same username and password?
Please encode the passwords. This is not ethic. You put at risk your members who uses same account information in somewhere else.
Try using a database which is stronger and faster than a text file.
How do I get other info from the user like location, birthday, or gender? I'm using this code as a guide for the project that I'm doing. http://windowsphoneaalto.org/2012/01/facebook-get-information-about-the-user/
I was able to get the user's id and name but I can't get the other information. I tried getting the user's location by adding, string location = result["location"].ToString();
I ended up getting a null value and a keynotfoundexception. This is the piece of code that I'm having issues with.
void _fbClient_GetCompleted(object sender, FacebookApiEventArgs e)
{
//Turn the data into Dictionary.
//If you want to see what the Facebook is returning you can check it
//with this tool provided by Facebook
//http://developers.facebook.com/tools/explorer/?method=GET&path=me
var result = (IDictionary<string, object>)e.GetResultData();
//Get the ID value
string id = result["id"].ToString();
//Get the name value
string name = result["name"].ToString();
//Currently the thread running this code
//is not the UI thread and only UI thread can update
//UI. So we are calling the UI thread here.
_page.Dispatcher.BeginInvoke(() => {
MessageBox.Show(name + " (" + id + ")");
});
As far as i remember you'll need to add that to the facebook apps extended permission and then ask the user to give you the rights to share those details.
Look more for extended permission on facebook will solve your problem
Everytime users did something like add, delete or edit data.
I want to keep the record of it. So system admin can see who did what later.
For example
private AddUser(User id)
{
if(id != null)
{
MessageBox.Show("Item Updated");
string sqlAddUser = "INSERT INTO 'DATABASE.USER' VALUES (Item.ID, Item.Name, Item.Address)";
if(db.SqlNonQuery(sqlAddUser) //If successful
{
///To DO : Add system log into database
///Ex. string sqlLog = DateTime.Now + User.ID + " added Item ID " + item.ID;
}
else
{
MessageBox.Show("Error");
}
}
}
Is there any better way or common practice to do it? Thank you.
In general for logging, I recommend Log4Net; it's highly configurable and works great.
However, if you don't want to invest the time in implementing a third-party component and wanted to log to the database, you could do your data access via stored procedure, and have an INSERT into a logging table as part of the SP.