Can't get Unity Firebase userID - c#

I'm trying to save the user data to the firebase realtime database directly after the user has been created. But the problem is not the saving, but the UserID. I save also save the user ID that i get from CurrentUser. and then i check in the realtime database and saw that the ID that stored was from a last user who recently created. And i check it in the editor by getting the current user Email and it showed the last user Email not the current user who are creating at the moment. Can someone help me to get the current user ID and not the last user id.
You guys can see the image from the links.
What ID should be
The last user ID showing up instead You guys can see that the ID don't event match. I did try redo the project and looking at the videos that from firebase it self. I really have no ide what to do, i am stuck for 3 days now.
public void SaveNewUserInCode(string userId, string Name, string Email) {
var currentUser = FirebaseAuth.DefaultInstance.CurrentUser;
string userNameId;
if (currentUser != null)
{
userNameId = currentUser.Email;
user = new User(userId, Name, Email);
string Json = JsonUtility.ToJson(user);
reference.Child("Users").Child(currentUser.UserId).SetRawJsonValueAsync(Json);
Data.text = userNameId;
}
}

It would be helpful to see the code that invokes SaveNewUserInCode.
I see a few potential dangers with the code you've posted:
The first is that any call (other than Auth.SignOut) is asynchronous. If you're caching userId immediately after Auth.SignInWithEmailAndPasswordAsync, you'll likely have the previous user still in Auth.CurrentUser (until the related task completes). See my related post on all the ways to wait for a task in Unity if you think this is the issue.
The second, especially if Email is sometimes null, you may be automatically calling Auth.SignInAnonymouslyAsync every time your app starts (perhaps old logic, I usually start my prototypes with anonymous users and later on add real accounts when it's time to do some user testing). This will always overwrite your current user even if you were previously signed in anonymously. You should always check Auth.CurrentUser before calling any of the Auth.SignIn methods, but definitely make sure that you don't have a stray Auth.SignInAnonymouslyAsync laying around.
If the issue is threading, I believe the following logic will fix your problem:
var auth = FirebaseAuth.DefaultInstance;
auth.SignInWithEmailAndPasswordAsync(email, password).ContinueWithOnMainThread(task => {
// omitted : any error handling. Check task's state
var user = task.Result;
SaveNewUserInCode(user.UserId, user.DisplayName /* or however you get Name */, user.Email);
});

Related

The command to get avatar is not working correctly (Problem with SocketGuildUser maybe)

A very simple command to get the user's avatar. However, it works unstable and incorrectly (example in the screenshot). Bot does not respond to all users and not every time. What can this be related to? Maybe I don't understand something, but in my opinion, there is a problem with SocketGuildUser. Here is a simplified code snippet for clarity:
[Command("avatar")]
[Alias("getavatar")]
public async Task GetAvatar(ushort res, SocketGuildUser user = null)
{
if (user == null)
{
await Context.Channel.SendMessageAsync(Context.User.GetAvatarUrl(size: res));
}
else
{
await Context.Channel.SendMessageAsync(user.GetAvatarUrl(size: res));
}
}
Simply enable intents in the discord developer portal. Without it, users will not be cached and your user type reader will fail to parse any mentioned users
Edit: An alternate method would be to create your own custom type reader that will fallback to making a rest request if fetching the user from cache yields no results.

Clarifications and peer review regarding authentication and roles of my web application

I am trying to learn basic security and access limitations on ASP MVC.
So far, i have read/watched tutorials but all of them seems different from one another. If i will search something, it will lead me to another implementation which is totally different from what i have.
I implemented Authentication and custom role provider and i have some questions regarding how things work. Majority of explanations that i found from the internet seems overly complicated or outdated.
This is how i implemented my authentication.
login controller:
[HttpGet]
[ActionName("login")]
public ActionResult login_load()
{
return View();
}
[HttpPost]
[ActionName("login")]
public ActionResult login_post(string uname,string pword)
{
using (EmployeeContext emp = new EmployeeContext())
{
int success = emp.login.Where(x => x.username == uname && x.password == pword).Count();
if (success == 1)
{
FormsAuthentication.SetAuthCookie(uname, false);
return RedirectToAction("Details", "Enrollment");
}
return View();
}
}
Then i protected most of my controllers with [Authorize]
Question #1
What's the purpose of FormsAuthentication.SetAuthCookie(uname, false); and what should i typicalfly use it for? would it be alright to store the username. Do i need it for comparison later on?(further security?). It says here that Authentication ticket will be given to the username. Are those the ones with random letters?
--
After that, i decided to dive deeper and implemented a custom role provider
from roleprovider.cs(I only implemented 2 methods so far)
public override string[] GetRolesForUser(string username)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
return null;
}
var cacheKey = username;
if (HttpRuntime.Cache[cacheKey] != null)
{
return (string[])HttpRuntime.Cache[cacheKey];
}
string[] roles = new string[] { };
using (MvcApplication6.Models.EmployeeContext emp = new MvcApplication6.Models.EmployeeContext())
{
roles = (from a in emp.login
join b in emp.roles on a.role equals b.id
where a.username.Equals(username)
select b.role).ToArray<string>();
if (roles.Count() > 0)
{
HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);
}
}
return roles;
}
Question #2
I am kinda confused here and i need a deep clarification: so what is basically the purpose of the cacheKey and from my example, i just made it equal to uname since i have no idea what's going on.
Question #3
Why is it returned (string[])HttpRuntime.Cache[cacheKey]; if the value is null? when is it returned and who is receiving it?
Question #4
After getting the value the list of roles from the database, this function will be called HttpRuntime.Cache.Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);. So from what i see, the roles are being inserted into the cache? is it for checking the login type later on?
Question #5
from this lines of code:
public override bool IsUserInRole(string uname, string roleName)
{
var userRoles = GetRolesForUser(uname);
return userRoles.Contains(roleName);
}
When are they exactly triggered and who provides the parameters? is the roleName from the cache?
I am having a hard time visualizing what's happening under the hood. Explanations/Referrals will be very helpful.
What's the purpose of FormsAuthentication.SetAuthCookie()?
This is ASP.NET FormsAuthentication's built-in method for dealing with authentication cookies.
How does cookie based authentication work?
Explained: Forms Authentication in ASP.NET 2.0
Basically, it's doing the hard work for you; creating a cookie for a specific user, giving it to them and then using it to recognise the same user in the future. You want to use this function to log a user in (if they enter correct credentials).
The string parameter is for a username. Yes, you can use username.
The bool parameter is for if you want the cookie to be persistent. That is, keep them logged in even if they close the browser (whether or not to use a session).
By using FormsAuthentication in this way, ASP.NET will automatically detect the user again when they visit subsequent pages.
What is basically the purpose of the cacheKey?
The Cache component of the HttpRuntime is for managing a "box" of objects that you might retrieve frequently but don't want to be hitting the database all the time for.
The Cache is implemented as a kind of Key-Value Pair. The cacheKey in your example is a key in the Key-Value collection. You can think of it like other similar data structures used in other languages.
{
"carlobrew": {
"roles": {
"Name": "Administrator"
}
}
}
So you're basically "saving" the roles of the user carlobrew in a container so that you can get them again later. The key in a Key-Value Pair is used to refer back to the data that you put in there. The key you are using to refer back to the saved information is the uname; that is, the username.
The key in Key-Value Pairs is unique, so you cannot have two keys called carlobrew.
Why is it returned (string[])HttpRuntime.Cache[cacheKey]; if the value is null?
There are two steps to using a typical "cache box" like this.
If we find the key (such as the user carlobrew) then we can simply return the data straight away. It's not if the value is null. It's if the value is not null. That's why the code is if (HttpRuntime.Cache[cacheKey] != null).
If the key cannot be found (that is, we don't have the key for carlobrew), well then we have to add it ourselves, and then return it.
Since it's a cache, ASP.NET MVC will automatically delete things from the cache when the timer expires. That's why you need to check to see if the data is null, and re-create it if it is.
The "who is receiving it" is whichever object is responsible for calling the GetRolesForUser() method in the first place.
So from what i see, the roles are being inserted into the cache?
Yes.
Basically, if the data isn't in the cache, we need to grab it from the database and put it in there ourselves, so we can easily get it back if we call the same method soon.
Let's break it down. We have:
Insert(cacheKey, roles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinute), Cache.NoSlidingExpiration);
Insert is the method. We're calling this.
cacheKey is the key part of the Key-Value Pair. The username.
roles is the object that we want to store in cache. The object can be anything we want.
DateTime.Now.AddMinutes(_cacheTimeoutInMinute) is telling ASP.NET MVC when we want this data to expire. It can be any amount of time that we want. I'm not sure what the variable _cacheTimeoutInMinute maybe it's 5 or 15 minutes.
Cache.NoSlidingExpiration is a special flag. We're telling ASP.NET that, when we access this data, don't reset the expiration timer back to its full. For example, if our timer was 15 mins, and the timer was about to expire with 1 minute to go, if we were using a sliding expiration and tried to access the data, the timer would reset back to 15 minutes and not expire the data.
Not sure what you mean by "is it for checking the login type later on". But no, there isn't any checking of login type here.
IsUserInRole
You would probably call this when the user is trying to do something. For example, if the user goes to /Admin/Index page, then you could check to see if the user is in the Administrator role. If they aren't, you'd return a 401 Unauthorized response and tell you the user they aren't allowed to access that page.
public Controller Admin
{
public ActionResult Index()
{
if (!IsUserInRole("Administrator"))
{
// redirect "not allowed"
}
return View();
}
}

other user's profile not populating

I've got a weird issue going on. I'm calling the profile for another user (not the currently authenticated user) and trying to access a value.
var profile = System.Web.Profile.ProfileBase.Create(username, true);
if (profile.PropertyValues["x"] != null)
ddlList.SelectedValue = profile.PropertyValues["x"].PropertyValue.ToString();
The value 'x' does exist for the user, but it's returning null. If I step through the code, and actually view the profile values before the if statement, then it works as expected. So I have to explicitly step through the code and view the value for the app to actually acknowledge it.

C# MVC4 windows username and cookie issues

First, I'm sad to say I'm not sure whether this code should be in the _Layout.cshtml or somewhere in the controller. It needs to run on all pages, so I've put it in the _Layout.cshtml page.
This is for an intranet web app. What I'm attempting to do is this: if a cookie (holding the user's userid) is not found, get the windows username, run it through a class that will go into the database and get the corresponding user's username, and - if we get a user id back - make a cookie containing it. Doesn't sound too hard, but one line in particular, and various incarnations of it, is refusing to be supportive. Here's the code as a whole.
if(!Context.Response.Cookies.AllKeys.Contains("userid")){
var winuser = System.Web.HttpContext.Current.User.Identity.Name;
var winuserid = myprojectname.Models.MyIntranetDataContext.getUserId(winuser).UserID();
if (winuserid == null) {
Response.Redirect("/someotherpage");
} else {
HttpCookie cookieuser = new HttpCookie("userid");
DateTime now = DateTime.Now;
cookieuser.Value = winuserid;
cookieuser.Expires = now.AddMonths(1);
Response.Cookies.Add(cookieuser);
}
}
Line 2 - var winuser... - appears to be the problem. In this current incarnation, I'm getting a build error: An object reference is required for the non-static field, method, or property 'myprojectname.Models.MyIntranetDataContext.getUserId(string)'
It doesn't like it when I add a .ToString to it either.
I've tried making winuser this as well:
Page.User.Identity.Name;
That gave no build errors. When I attempt to Start Debugging, she blows up with this beauty of an error: 'Cannot perform runtime binding on a null reference'
Once I get the windows username, all will be well.
Really, this isn't about cookies, or even mvc to much of an extent (except maybe guidance on where to put this code - the _Layout.cshtml?). Really it's about getting the windows username, which I seem unable to do. Thanks in advance for any assistance you are able to provide.
Note, the above names aren't actual - just for example only.
If they are on the domain, couldn't you use something like the following to retrieve that information?
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal principal = (WindowsPrincipal)Thread.CurrentPrincipal;
WindowsIdentity identity = (WindowsIdentity)principal.Identity;
String userName= principal.Identity.Name;

How to refactor procedural code?

I am creating a password reset feature for web site. First step for password reset have to be implemented:
User enters his email in password reset form.
System checks if user with email is registered.
If user has been found, system sends email with password reset URL with uniqe token.
If user is not found, system sends email notifying that password reset was initiated for this email, but user account doesn't exist.
I have service class which implements public method - RequestPasswordReset and this method is quite procedural:
public void RequestPasswordReset(string email)
{
if(!IsValidEmail(email))
{
throw new ArgumentException("email");
}
var user = this.repository.FindByEmail(email);
if(user != null)
{
user.PasswordResetToken.Set(this.tokenGenerator.NewToken());
this.emailService.Send(this.from,
user.Email,
"Password reset",
"Your reset url: http://mysite.com/?t=" +
user.PasswordResetToken.Value);
}
else
{
this.emailService.Send(this.from,
user.Email,
"Requested password reset",
"Someone requested password reset at http://mysite.com");
}
}
This method violates Single Responsibility Principle - it checks user existence, resets user token, sends emails.
The main issue with such solution is that if I need to add additional steps I have to add implementation for those to RequestPasswordReset method and method becomes more and more complex.
Additional steps could be, for example, to check if user is registered in another related system already and I could advise him create new account in my system or create user account for him.
I was looking at Command pattern - it might be good to refactor service class into separate commands and RequestPasswordReset could be one of those commands. But it doesn't solve main issue with steps inside RequestPasswordReset method.
I was also looking at Chain of Responsibility pattern - it would be good to handle steps in order, but I do not know how it could be used to handle control flow - different conditions which should be implemented. Also it looks like that each handler should do similar actions and it will be not clear how the whole control flow changes.
What would be best approach to refactor such procedural code?
This method violates Single Responsibility Principle
Actually I don't think it does. The "single responsibility" of the service is to reset a user's password, and it does this quite well by coordinating with other objects (user repository and mail service). If the process of resetting a password changes, then this class will change and there is nothing wrong about that.
I think your code is fine as it is. If you absolutely want to refactor something, you might split the code up a little more just to simplify readability of the main method; something like this:
public void RequestPasswordReset(string email)
{
ValidateEmail(email); // May throw exception if invalid
var user = this.repository.FindByEmail(email);
if(user != null)
{
GenerateTokenAndSendPasswordResetEmail(user);
}
else
{
SendPasswordResetEmail(email);
}
}
Other than that, I would leave it as it is. Your problem is really quite simple, so there is no reason to look for a complex solution! :)
The best thing to do with this code is to ensure that it is thoroughly tested. Ensure that all code paths have been tested.
And then, get over it!
Get over the idea that all code has to abide by design patterns, single responsibility principle and other such stuff. Those patterns were discovered by examining working code.
You've got working code here. Get over it and get onto the next task.

Categories