angularjs redirection after login - javascript

may I know how to redirect user to where they originally at after login ? say i have a post wwww.example.com/post/435 and it required user to log in in order to "like/comment" the post, so after the user login how can i redirect user back to the post ? i have tried this
$http.post('/sessionHandler/login',$scope.form).
success(function(data){
history.back(); // bring user back to previous path
}).error(function(err){
$scope.errorMessage = err;
});
however this is not really effective, if a user previous path is other site or a browser new tab it will redirect the user back to where they are.
i also found some example by using $locationChangeStart but i'm having some difficulties to understand how it works this is what i have so far for $locationChangeStart
$http.post('/sessionHandler/login',$scope.form).
success(function(data){
$rootScope.$on("$locationChangeStart", function (event, next, current) {
$location.path();// how to access to previous url where the user from ?
// how to use event, next and current to get the user last
// path on my site, and how to determine the last site is
// on my site but not other website ?
});
})
your help is appreciated !!

May not be the best answer, but I use a cookie for this - so whenever I'm redirecting to a new location, I'll use $cookies.loginDestination = $location.path(), then whenever a user logs in, I use something like:
var loginDestination = $cookies.loginDestination || '/';
$cookies.loginDestination = null;
$location.path(loginDestination);

Related

Refresh page on new user sign in when using Google oAuth 2.0

I'm trying to make a website using Google Sign For Websites. Mostly just for the sake of learning about how it works.
I've followed the steps outlined in that tutorial Google Provides which works fine. Users can successfully sign into my site, it is able to pass the users ID to the backend and then verify the ID server side using a php script.
Php then creates a session for the user on the website. What I can't figure out is how would I refresh the page when a user clicks the Google Sign in button and the sign in is successful. Refreshing the page would allow the home page to be reloaded with the new php session data.
<div class="g-signin2 signin-button" data-onsuccess="onSignIn" data-theme="dark"></div>
function onSignIn(googleUser){
// The ID token you need to pass to your backend:
var id_token = googleUser.getAuthResponse().id_token;
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://mywebsite.com/tokensignin.php');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('idtoken=' + id_token);
};
I've tried using simply location.reload() inside of the onload = function() portion of the code. This causes the page to just infinately refresh every time it is loaded however since Google verifys that the user is signed in through this xhr variable every time.
I've tried looking through their reference to use GoogleAuth.isSignedIn.listen(listener) to monitor any changes but it doesn't seem to fullfull what I want it to or I'm not using it correctly since I don't exactly know what the listener should be.
The other option might be to use their GoogleAuth.attachClickHandler(container, options, onsuccess, onfailure) function but I'm not entirely sure how the properly configure the options field/variable.
If someone could provide some insight as to how this world work I would greatly appreciate it.
To summarize if the user is already signed into my website using Google I want the page to do nothing, if they click the signin button, after the sign in is successful I want to refresh the page they are on.
You could add a listener to xhr with a callback function.
xhr.addEventListener("load", loginComplete);
And then create a function:
function loginComplete(evt) {
console.log("Login Complete");
window.location.reload();
}
EDIT:
Ok. Since the listener doesn't help. You will need to check if the user is already logged in. To save that information one thing I could think of would be using cookies.
So you could store the Auth Token you receive from Google and set a cookie for it and check everytime before you make your POST.
Here is a nice js cookie library: https://github.com/js-cookie/js-cookie
Then onload you save the id:
xhr.onload = function() {
Cookie.set('google_token', id_token);
window.location.reload();
};
And the onSignIn function would be like:
function onSignIn(googleUser){
var cookie = Cookie.get('google_token');
if(cookie != undefined){
//cookie is set
return;
}
...
//rest of the function
}
Of course you need to improve this code, for example, check if the token stored in the cookies is still valid, some cases you can just refresh it instead of making the user log in again (the oAuth API provide such things).
Make some security measures to be sure the token is not being injected and etc..
My approach was the same as yours and I indeed ran into the same problem with constant refreshing.
I tried a couple of solutions, the best working one was as follows:
User signs in using GAPI2 triggering callback onGoogleSignIn
Backend checks ID token validity, and signs user in through session on my webapp
If successful, I log the user out using GAPI2, preventing infinite reload, because onGoogleSignIn is never called again
Then I refresh the page and replace the sign-in button with a logout button for my webapp
This solution is of course pretty much useless if you want to manipulate some data on user's Google account, but I found no use for this functionality.
Code for signing someone out of their google account.
function signOut() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
});
}
Why not have your back end redirect (or send info so the page so it can redirect on success)?
What is the need for reloading the login screen?
You could also check out the listener documentation it seems like this may solve what you want. ie. listen for user change and trigger a function or redirect.
https://developers.google.com/identity/sign-in/web/listeners

Detecting Unique Browser Tabs

On every page of my sites, I am using AJAX to poll the server and retrieve a list of messages. The server maintains a list of messages and the SessionId (I'm in an ASP.NET environment, but I feel like this question is applicable to any server side technology) that the message is intended for. If a message is found for the particular SessionId, it is returned to the client side script. I use a JavaScript library to create a notification (using noty, a Jquery Notification Plugin). Once it returns a particular message, the server discards that message.
This works well if the user only has a single tab/window open for a particular site. However, let's say they have two open and they do something that causes a warning message to be generated. I have no control over which tab the notification goes to, so the user may not end up seeing the warning message.
Is there a way of uniquely identifying a browser tab? Then I could pass this as one of the parameters in my AJAX call.
Firstly, polling doesn't seem good mechanism. It might hit your server down when you have large number of active users. Ideally you should return a message in the response to the request that was result of invalid action.
Still below solution might work for you. It is inspired by the reply of #SergioGarcia.
Keep a hidden input just before the end of your form tag, which stores a unique ID for identifying a tab uniquely. You will store the messages on server session against unique tabID,
<input type="hidden" id="hiddenInputTabId" value="<%=getValue()%>" />
and then define getValue.
function string getValue() {
var v = getValueFormBodyOrAccessValueDirectlyByMakingInput_a_ServerSideControl();
if (string.IsNullOrWhiteSpace(v)) {
return Guid.NewId();
} else {
return v;
}
}
Because it is a hidden input you should get it's value in the POSTed form body, and for ajax requests below snippet should take care of sending that value in header which you can access on server side.
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("tabId", $('#hiddenInputTabId').val());
},
});
Same header can be check while returning the response to your polling requests and only respond message available against the provided tabId should be responded.
You can add a query string parameter called tabId and control it's binding to tab using javascript.
There is a functional prototype below:
$(function () {
// from: https://developer.mozilla.org/en-US/docs/Web/API/Window.location
function getQueryStringParameter (sVar) {
return decodeURI(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURI(sVar).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
}
// from: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
function newGuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
window.tabId = getQueryStringParameter('tabId');
// tabId not defined, reload the page setting it
if (!window.tabId) {
window.tabId = newGuid();
}
// on click set the tabId of each link to current page
$(document).on('click', 'a', function (e) {
var $this = $(this);
var newLocation = $(this).attr("href");
// In page links
if (newLocation.match(/^#.+$/)) {
return;
}
// Outbound links
if (newLocation.match(new RegExp("^https?")) && !newLocation.match(new RegExp("^https?://" + window.location.host))) {
return;
}
// Insert tab id
if (newLocation.match(/(\?|&)tabId=[0-9a-f-]+/)) {
newLocation.replace(/(\?|&)tabId=[0-9a-f-]+/, (newLocation.indexOf('?') == -1 ? "?" : "&") + "tabId=" + window.tabId);
} else {
newLocation += (newLocation.indexOf('?') == -1 ? "?" : "&") + "tabId=" + window.tabId;
}
window.location.href = newLocation;
e.preventDefault();
});
});
If you enter a page in your application without setting the tabId parameter on query string, it will be set to a new UUID (Guid).
When the page has a tabId parameter on query string, it defines the window.tabId variable inside your page and you can use that in your application.
When the user click on any link in your page, a javascript event will be triggered and the link url will be redirected to match the current tabId. An right click to open in new tab or a middle click will not trigger that event and the user will be sent to a new tab without the query string parameters, so the new page will create a new tabId in that page.
You can see it working here: http://codepen.io/anon/pen/sCcvK
You can do it by generating a unique tab id with javascript by loading your client.
I strongly recommend you to use something for intertab communication, like intercom.js, which can broadcast the messages from a single tab with a single connection to every other tabs. Intertab works with socket.io, which has long polling fallback, so it may be good in your current system as well. I agree that polling is a poor choice, and you should use websockets instead.
If you use ZMQ on the server, then in the browser you can use NullMQ either (for websockets ofc). I think it does not have intertab support, so you should make your own intertab solution to make it work. It is not so hard to write such a system, you need only a common storage, for example localStorage, but it can be even cookie... If you don't have a storage event, you have to ping that storage for changes with setInterval. You have to store there the messages, and which tab broadcasts them (probably in a semaphore) and when was the last time it pinged the storage. After that you can keep each tab in sync with the others, or by using a unique tab id, you can send customized messages to any of the tabs. If the broadcast tab has a storage timeout (it did not ping the storage for a long while), then it is probably closed, so you should assign the broadcast service to another tab.
So what I ended up doing was changing how my notification framework functioned in order to prevent the need for identifying unique tabs. It's just too hard to layer information on the stateless web.
Instead of using Ajax to pump messages out to the client instantly, I build them up on each page into a List<Message> property. On PreRender I render them to the client with ClientScript.RegisterStartupScript(). But if I need to send the user to another page, I started using Server.Transfer() instead of Response.Redirect() instead so that it will preserve the message queue. The new page checks the old page to see if it exists and if is the correct Type. If it is the correct type, I cast it and retrieve the message queue from the old page and add them to the new page's queue. And since Server.Transfer() doesn't update the URL on the client, I also added a JavaScript function to manually push the state to the URL in supported browsers.
I know I took this in a little different direction than I did on the question, but I think I had been approaching it wrong in the beginning.

Facebook login redirect issue

I have a site with a working Facebook login.
The problem is happens when the user comes to the site for the first time (or after clearing cookies).
The user flow is the following:
User clicks "Sign Up with Facebook"
User is redirected to Facebook authentication
If User accepts, he/she is redirected to the 'Sign Up' page.
The problem is that if the person is doing this for the first time, they are always redirected back to the home page.
There are only 2 possible views that can be given for this url
The Sign Up page, with only some form data sent as parameters
An alert box upon successful DB persistence
Thus, I have ruled out PHP as a possible cause of the redirect.
I have included the JavaScript managing the Facebook interaction.
All other relevant code can be found in the HTML of the page.
The Page can be found at http://trioisrael.com
function fb_login(){
FB.login(function(response) {
if (response.authResponse) {
window.location = "http://trioisrael.com/signup"
//console.log(response); // dump complete info
access_token = response.authResponse.accessToken; //get access token
user_id = response.authResponse.userID; //get FB UID
FB.api('/me', function(response) {
user_email = response.email; //get user email
// you can store this data into your database
});
} else {
//user hit cancel button
alert('We use facebook to make sure that everyone is really who they say they are');
}
}, {
scope: 'user_photos,user_birthday'
});
}
Trying to do additional stuff after assigning a new value to window.location (which should be window.location.href, of course) does not make sense.
If you want to do additional stuff after login, do it before redirecting the user somewhere else.

Setup page on first login, express.js

I'm using Passport.js to authorize user into my express.js app.
I want to show setup page when user logins first time.
Can I do this with Passport?
This Code MUST be modified mor your db, etc.
Init The User:
var user = new User({ ... });
user.newUser = true;
And
app.get("/account",requireLogin, function(req,res){
if(req.user.newUser){
req.user.newUser = false;
req.user.save(function(err){
if(err) return handleError(err);
res.redirect("/setup");
})
}
})
You need to place newuser attribute within the database as answered by "Ari Porad" but the better approach would be to change it to false when you are done with account first time setup because we dont really know if the user has completed his first time setup or not (browser may crash and he might not be able to complete it :D ) , so its better not to modify the "newuser" attribute as false on first visit but rather you should be modifying it after he has submitted the data that we require on the first visit.

Facebook Connect - Single Sign On Causes Infinite Loop :(

I have a Facebook Connect (FBML) web application that has been live for a while now.
All is working well, however user's are reporting issues with the single sign on (and i have seen the issue on their computer, but have not been able to replicate locally).
With FBC, there is a "event" you can hook into to automatically determine if the user is authenticated to Facebook.
That is achieved via this:
FB.Connect.ifUserConnected(onUserConnected, null);
The onUserConnected function can then do whatever it needs to attempt a single sign on.
For me, what i do is a AJAX call to the server to see if the user has an active website account (based on the Facebook details - user id, which i store in my system when they connect).
If they do, i show a jQuery modal dialog ("Connecting with Facebook") and do a window.location.reload().
The server then kicks in, and does the Single Sign On. This code is executed on every page:
public static void SingleSignOn(string redirectUrl)
{
if (!HttpContext.Current.Request.IsAuthenticated) // If User is not logged in
{
// Does this user have an Account?
if (ActiveFacebookUser != null)
{
// Get the user.
var saUser = tblUserInfo.GetUserByUserId(ActiveFacebookUser.IdUserInfo);
if (saUser != null)
{
// Get the Membership user.
MembershipUser membershipUser = Membership.GetUser(saUser.UserID);
if (membershipUser != null && membershipUser.IsApproved)
{
// Log Them Automically.
FormsAuthentication.SetAuthCookie(membershipUser.UserName, true);
// At this point, the Forms Authentication Cookie is set in the HTTP Response Stream.
// But the current HTTP Context (IsAuthenticated) will read HTTP Request Cookies (which wont have the new cookie set).
// Therefore we need to terminate the execution of this current HTTP Request and refresh the page to reload the cookies.
HttpContext.Current.Response.Redirect(
!string.IsNullOrEmpty(redirectUrl) ? redirectUrl : HttpContext.Current.Request.RawUrl,
true);
}
else
{
HandleUnregisteredFacebookUser();
}
}
else
{
HandleUnregisteredFacebookUser();
}
}
else
{
HandleUnregisteredFacebookUser();
}
}
}
I have never experienced an issue with this, but user's are reporting an "infinite" loop where the dialog gets shown, the window is refreshed, dialog is shown, window is refreshed, etc.
Basically, my AJAX call is saying the user exists, but my single sign on isn't.
Which is hard to believe because the code is very similar:
This is the AJAX Web Service:
if (!HttpContext.Current.Request.IsAuthenticated) // If user is not yet authenticated
{
if (FacebookConnect.Authentication.IsConnected) // If user is authenticated to Facebook
{
long fbId;
Int64.TryParse(Authentication.UserId, out fbId);
if (fbId > 0)
{
tblFacebook activeUser = tblFacebook.Load(facebookUniqueId: fbId);
if (activeUser != null && activeUser.IsActive) // If user has an active account
{
return true;
}
}
}
}
So if the response of this WS is 'true', i do a window.location.reload();
So i have no idea what the issue is (as i cant replicate), sounds like the Single Sign On isn't adding the Forms Authentication cookie properly to the response stream, or the Response.Redirect(Request.RawUrl) isn't reloading the cookie properly.
How do other's handle this?
This is what should happen:
User logs into Facebook (on Facebook itself)
User comes to my site (which has been previously authorised)
My site compares the FBID with the FBID in my DB, and signs them in.
My site is an ASP.NET 4.0 Web Forms application, using the "old" Facebook Connect JavaScript API (FeatureLoader.js), and Forms Authentication.
The only other solution to an AJAX call/window.reload i can think of is an AJAX UpdatePanel.
Can anyone help me out?
EDIT
Also, i realise that i can also use 'reloadIfSessionStateChanged':true to do the reload (which stops the infinite loop), but the problem with this is i cannot show my nice fancy dialog.
So i found a couple of issues.
Firstly, i shouldn't be setting a persistent cookie:
FormsAuthentication.SetAuthCookie(membershipUser.UserName, true);
We should only do this when the user ticks a box such as "Remember Me".
Secondly, i was checking the FB Auth status on every page on the server, so this could have been getting out of sync in the client-side.
Here is my new solution - which is better, and has a failsafe for the dreaded 'infinite loop'.
I no longer check the FB Auth status on the server, i do on the client:
FB.Connect.ifUserConnected(onUserConnected, null); // runs on every page request, on client-side
In the onUserConnection function i do the following:
Call web service to see if user CAN be signed in automatically (same WS as above)
If ok, check a special "Single Sign On" cookie has not been set.
If it hasn't been set, redirect to FacebookSingleSignOn.aspx.
FacebookSingleSignOn.aspx does the following:
Signs the user in using Forms Authentication (same as above)
Creates a special "Single Sign On" cookie to signify a SSO has been attempted
Redirects to the homepage
So, at point 3 above - this is where the infinite loop "could" happen. (as the onUserConnected will run again)
But it is now impossible (i hope) for it to happen, as it will only attempt to do the SSO if they havent already tried.
I clear the SSO cookie on the Facebook Logout action.
Now works well, logic makes sense - and it's done on the client-side (where it should be, as this is where FB does it's magic).
Hope that helps someone else out.

Categories

Resources