I have a question regarding CodeCamper app by John Papa. In the config.js
file, the currentUserId value is hardcoded to 3. I want to set this value with
the SQL employee table unique id after it has authenticated using a Login
page.
The login page is already working, I just need to set the currentUserId value to make it all work, anyone has an elegant solution?
Thanks
You can add an API action that returns the currentUserId.
In your config.js, just add a loadUser function to get the currentUserId from the API and then update the currenUserId variable accordingly.
This loadUser function should be called after the user has been authenticated. Without more details on how you do the authentication, I won't be able to say where exactly this should happen.
Related
I'm working with the SAFE stack (https://safe-stack.github.io/) and through the example dojo. It's great so far.
I'd like to extend the example to include a button to login/auth via Google. So I looked at an example on the Google website (https://developers.google.com/identity/sign-in/web/build-button). And then I had a look how to do authentication using ASP.NET (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-2.1&tabs=aspnetcore2x) As a result I ended up confused as to how to integrate this into a SAFE project. Can someone tell me what they would do? SHould I be trying to use ASP.NET Identity or should I be using the JWT approach? I don't even know if they are the same since I'm very new to web frameworks.....
The other question I have is how would one inject raw Javascript into the client side of a SAFE project. The google example above shows raw JS/CSS/HTML code? Should I be injecting that as is or should I look in React for some button that does this and map that idea back through Fable?
Setting up OAuth
The easiest way to use Google OAuth is to wait until the next release of Saturn, at which point Saturn will include the use_google_oauth feature that I just added. :-) See the source code if you're interested in how it works, though I'm afraid you can't implement this yourself with use_custom_oauth because you'll run into a type error (the underlying ASP.NET code has a GoogleOptions class, and use_custom_oauth wants an OAuthOptions class, and they aren't compatible).
To use it, add the following to your application CE:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" []
The last parameter should be a sequence of string * string pairs that represent keys and values: you could use a list of tuples, or a Map passed through Map.toSeq, or whatever. The keys of that sequence are keys in the JSON structure that Google returns for the "get more details about this person" API call, and the values are the claim types that those keys should be mapped to in ASP.NET's claims system. The default mapping that use_google_oauth already does is:
id → ClaimTypes.NameIdentifier
displayName → ClaimTypes.Name
emails[] (see note) → ClaimTypes.Email
Those three are automatically mapped by ASP.NET. I added a fourth mapping:
avatar.url → `"urn:google:avatar:url"
There's no standard ClaimTypes name for this one, so I picked an arbitrary URN. Caution: this feature hasn't been released yet, and it's possible (though unlikely) that this string might change between now and when the feature is released in the next version of Saturn.
With those four claim types mapped automatically, I found that I didn't need to specify any additional claims, so I left the final parameter to use_google_oauth as an empty list in my demo app. But if you want more (say you want to get the user's preferred language to use in your localization) then just add them to that list, e.g.:
use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" ["language", "urn:google:language"]
And then once someone has logged in, look in the User.Claims seq for a claim of type "urn:google:language".
Note re: the emails[] list in the JSON: I haven't tested this with a Google account that has multiple emails, so I don't know how ASP.NET picks an email to put in the ClaimTypes.Email claim. It might just pick the first email in the list, or it might pick the one with a type of account; I just don't know. Some experimentation might be needed.
Also note that third-party OAuth, including GitHub and Google, has been split into a new Saturn.Extensions.Authorization package. It will be released on NuGet at the same time that Saturn's next version (probably 0.7.0) is released.
Making the button
Once you have the use_google_oauth call in your application, create something like the following:
let googleUserIdForRmunn = "106310971773596475579"
let matchUpUsers : HttpHandler = fun next ctx ->
// A real implementation would match up user identities with something stored in a database, not hardcoded in Users.fs like this example
let isRmunn =
ctx.User.Claims |> Seq.exists (fun claim ->
claim.Issuer = "Google" && claim.Type = ClaimTypes.NameIdentifier && claim.Value = googleUserIdForRmunn)
if isRmunn then
printfn "User rmunn is an admin of this demo app, adding admin role to user claims"
ctx.User.AddIdentity(new ClaimsIdentity([Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, "MyApplication")]))
next ctx
let loggedIn = pipeline {
requires_authentication (Giraffe.Auth.challenge "Google")
plug matchUpUsers
}
let isAdmin = pipeline {
plug loggedIn
requires_role "Admin" (RequestErrors.forbidden (text "Must be admin"))
}
And now in your scope (NOTE: "scope" will probably be renamed to "router" in Saturn 0.7.0), do something like this:
let loggedInView = scope {
pipe_through loggedIn
get "/" (htmlView Index.layout)
get "/index.html" (redirectTo false "/")
get "/default.html" (redirectTo false "/")
get "/admin" (isAdmin >=> htmlView AdminPage.layout)
}
And finally, let your main router have a URL that passes things to the loggedInView router:
let browserRouter = scope {
not_found_handler (htmlView NotFound.layout) //Use the default 404 webpage
pipe_through browser //Use the default browser pipeline
forward "" defaultView //Use the default view
forward "/members-only" loggedInView
}
Then your login button can just go to the /members-only route and you'll be fine.
Note that if you want multiple OAuth buttons (Google, GitHub, Facebook, etc) you'll probably need to tweak that a bit, but this answer is long enough already. When you get to the point of wanting multiple OAuth buttons, go ahead and ask another question.
I have a Meteor app where I need to:
Create / update app users including their name, username and password. So I was wondering if first is it possible to do so while login to the app as a Meteor user? In other words is it possible to create / update other app users while logging in as an app user? I've tried to search for an example / how to but couldn't find any so any help will be highly appreciated.
Add custom fields to Meteor.users document (ex. User type(accountant / sales...etc), Phone...etc)? After research couldn't find any example except on how to update Meteor.users profile in update only, but couldn't find how to do so when creating the new user, so any help will be highly appreciated.
Thanks
To add fields to user simply use onCreateUser function
Accounts.onCreateUser(function(user) {
user.type = "customer";
user.phone = "123456789";
//etc
return user;
});
And I didn't understand first question, but you can update user data by making query, such as:
Meteor.users.update({_id:this._id},{$addToSet~});
I have managed to successfully configure this. The problem is, when I change the lines below :
//I have set all requested data with the user's username
//modify here with relevant data
$user->setUsername($username);
$user->setEmail($username);
$user->setPassword($username);
into the information I want to retrive, such as real name, email, my generated password etc, when I click the Login button for Facebook per say, I am asked again if I want to connect with my local testing site.
From what I understand, in the documentation I linked above, this :
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
is the line that checks if the user exists or not, and the initial code by itself, sets either facebook_id or twitter_id (this is how I save them) as a new User *username*. If I change the line
$user->setUsername($username); //same as facebook/twitter _id
into
$user->setUsername(setProperUsername()); //sets a proper unique username
Then everytime I try to login I get the "Register" message. So, I have a general idea of how it works but I am having a hard time understanding some things:
1. When I have registered with Facebook and I login with twitter, I register again, no knew row is created, but missing twitter_id fields are updated/populated, username stays intact. How come HWI/FOSUB knows I am the same person when my previous data were from Facebook not Twitter?
2. If there is a global way of knowing I am the same person, what data from the $response object should I use as a key to identify already registered users?
After testing a lot with this, I have the answer if anyone runs into this type of situation
Check your default_target path, make it so it is /profile, /account etc, don't default to login again. Also, if a user is already logged in, do not make him access your login page. This was why my data was being updated. I was basically logged in with my Facebook account and registering with my Twitter account too.
No, there is no global way of knowing I am the same person. The $response object sent me a unique ID for that specific user according to the provider policy. You might use this to identify already registered users and log them in.
I am building a User Management page and am trying to retrieve both the number of registered users and the number currently online using the following code.(FYI...I am using mySQL as the membership provider) There are currently 4 users in the asp_net_users table so at least 4 should come up on the GetAllUsers request.
lblOnlineUsers.Text = Membership.GetNumberOfUsersOnline().ToString()
lblTotalUsers.Text = Membership.GetAllUsers.Count.ToString()
The labels are always blank. Even if I put a MsgBox(Membership.GetAllUsers.Count.ToString()) in the pageload, that msgbox never comes up. Any thoughts on what I'm doing wrong here?
You valid your user credential with ValidateUser or UpdateUser method , and you re-test
I'm developing a ASP.NET site in umbraco, and I need to see if a member with a given ID is online. How can I do that?
So far, I've tried to get the member by so:
Member m = new Member(myID);
But how can I check, if the returned member is logged in or not?
EDIT: I followed the link, and extracted the following code from it:
var users = Membership.GetAllUsers();
foreach(MembershipUser user in users){
Response.Write(user.IsOnline.ToString() +"<br/>");
Response.Write(user.LastActivityDate.ToString() + "<br/>");
Response.Write(user.LastLoginDate.ToString() + "<br/>");
}
However, the returned result shows that the property isOnline is true for every member, even though they're not online. I'm aware that it is because of the fact that the LastActivityDate updates automatically whenever I access the user, as stated here: Is it possible to access a profile without updating LastActivityDate?. Unfortunately, I don't get the solution to that question.
I've also tried to access the member by:
MembershipUser m = Membership.GetUser('myID',false);
But even though I put false as the second parameter, the LastActivityDate still updates. How can I work around this? I should note that I work with ASP.NET v. 4.0 in umbraco 4.7 at a localhost.
Thanks!
:EDIT END
Best regards,
Brinck10
You can use the MembershipUser.IsOnline Property that show true if the current date and time minus the UserIsOnlineTimeWindow property value is earlier than the lastActivityDate for the user.
There is an example on the MSDN page.
relative:
Proper 100% IsOnline implementation for asp.net membership
How to check in ASP.NET if the user is online?
asp.net custom membership provider: IsOnline property
The solution to the problem:
(1) I made a costum field in the membertype called lastActivityDate.
(2) I placed a macro on the masterpage, update the member's lastActivityDate to the current time given that the member was online.
(3) On the validation page I checked if the lastActivityDate + CostumBuffer was bigger than DateTime.Now.
Thanks for your patience Aristos.