Scenario: I have an AngularJS app that uses Google's auth.
Depends on the resource, when Angular calls (my) backend, it can return a response asking for Oauth token.
In this case, Angular will show a popup (not a Bootstrap's modal dialog) with that redirect URL.
Google will authenticated, ask for permission, and send the user back to me.
There is a callback URL that will process the 'code' and get the real token. This callbak URL will be called inside that popup.
When I get the token, the popup should close itself, and notify Angular to try that last request again (now I have the token in user's session)
Problem: how can a popup emit an Angular event?
Actually, it doesn't need to be that $rootScope.$emit, but just a way to notify Angular.
I saw this option, but it doesn't seem good for Angular :(
you can use localStorage events, take a look at this demo: http://html5demos.com/storage-events
// this should be in the main page
$window.addEventListener('storage', function(event) {
if(event.key === 'login-notification') {
// got it!
// you can get the value from
// the notification with "event.newValue"
}
}, false);
// send the event with just a setItem from the popup
$window.localStorage.setItem('login-notification', 'ayy');
Create a service first.
app.service("servicee", function(){
return {
set : function(k,v){
this[k] = v;
},
get : function (k){
return this[k]
}
}
});
Now in the popup you can set the token in the service, now you have the value available throught out the app. Also you can $watch the specific key in the service and take some action when the value is set.
Related
I have put some push notifications in my code, in order to someone to be notified when an action is made. I made the back end with lib.net.webpush 3.1.0 with .net 4.5.2 in C#.
So far, the notification system is working very well, but there is something I can't succeed :
Within my service worker file (sw.js), using Angular 9, i want, when someone received the notification, that when a user click on it, he is redirect to the page from which it was sent.
first i made it like it (as i read in the doc):
self.addEventListener('notificationclick', function (event) {
const urlToOpen = new URL(event.notification.data, self.location.origin).href;
event.notification.close();
event.waitUntil(clients.openWindow(urlToOpen));
});
But i was always redirect to the "localhost://4200" and not to the complete url.
In order to test, i made this :
self.addEventListener('notificationclick', function (event) {
const urlToOpen = new URL(self.location.origin + "/#/rdc/rapports/2015");
event.notification.close();
event.waitUntil(clients.openWindow(urlToOpen));
});
and it worked. But i can't get the dynamic URL.
Does anyone knows how to get a dynamic URL within this file? Or how to be redirect to the page that sent the notification?
I also tried something like this here : notificationclick event service worker
But i really dont understand.
Thanks.
I just succeed in doing it.
So, for anyone in the same case as I was : within the service worker, you can't access the DOM, i wasn't able to get any ID or any path I was trying to aim in my code.
The solution was to, in my C# code, to add a "URL" property and parameter to my "SendNotification" funtion. Then, when i got a user, i can target his ID because it's already here.
Then, in my Angular code (within the service worker file), I just had to to this (i am storing my url in "data" here) :
self.addEventListener('notificationclick', function (event) { console.log("notif click event", event);
const urlToOpen = new URL(self.location.origin + event.notification.data);
event.notification.close();
event.waitUntil(clients.openWindow(urlToOpen)); });
An then, when i click on the notification, I am redirected to the desired URL.
I'm doing auth with facebook that opens new tab and redirects user to backend on port 8080 after he is authenticated. Then he gets redirected back to app. From there I want to close the window and call function on opener window window.opener.functionAfterFinish() that will let it know auth finished. Problem is that I have to have that function in index.html for it to work. If I create functionAfterFinish(): void{...} in component, it won't get called.
What are my options ? How should I put that function in component and get it executed ?
Well, I'll suggest you to use cookies.
Firstly, You need to create cookies while redirecting to the new tab.
For Example : this._cookieService.createCookie('fbCookies', 'success', 3);
Now, you need to check the cookies by using a set interval in the method where you'are getting the authentication response.
Example-
let interval = setInterval(function(){
let cookie = this._cookieService.readCookie('fbCookies');
if (cookie === 'success') {
newWindow.close();
clearInterval(interval);
}else if (cookie === null) {
clearInterval(interval);
newWindow.close();
}
}, 5000);
Thus, as soon as you'll get the success tab will be close.
You have to set your component service or method on the window object
Inside your service/component :
askFacebook(){
(window as any).functionAfterFinish=this.functionAfterFinish.bind(this);
// Do ask facebook
}
Be sure to run the callback in the angular zone.
(Sorry for brevity, i am answering on my phone. If you have questions, don't hesitate to post a comment)
I am using Meteor with React and is facing a problem on log out function. When I open more than 2 tabs on the same browser, If I logged out from one tab then the other opening tabs would not be logged out but will be hang if I using it. There are only 2 ways to log out: close the tab or refresh it.
I try the same for log in function and it worked, log in status is synced between all opening tabs.
My current code to call the log out function:
signOut: function(event) {
event.preventDefault();
Meteor.logout();
this.props.history.pushState(null, "/");
},
Thank for the helps.
Update:
I checked the websocket, it's seem that the server did send the logout status but my client code did not call the logout method (or it is hang). Then every data in the hang tab is still existing. But I don't know how to check further more.
I found the cause. It was because I try to avoid sending data on Meteor.publish() if users is not logged in. The problem is I do not return anything on that case.
My solution is return this.ready() when the user is not logged in like this:
Meteor.publish("myCollections", function (){
if (!this.userId) return this.ready();
return MyCollections.find({owner: this.userId});
});
From the meteor documentation, you can use Meteor.logoutOtherClients() before calling Meteor.logout().
Normal (as in non-incognito) browser tabs share the same session resume token. The Meteor server will update them all when the user status changes for the associated session.
It is possible to reactively track the login status using 2 reactive calls:
Meteor.userId() - return the user's id or null if no user is logged in.
Meteor.loggingIn() - returns true if the user is currently in the transient state of logging in and false otherwise.
The status may take a few seconds to update across tabs, but it will happen eventually. It is up to you to detect those changes and act upon them.
You can easily test this by running the following reactive code in the consoles of 2 open tabs connected to the same Meteor server:
Tracker.autorun(function() {
if (Meteor.loggingIn()) {
console.info('logging in');
} else if (Meteor.userId()) {
console.info('logged in');
} else {
console.info('logged out');
}
});
Try to log in and log out from one of the tab and watch the other follow along.
Using this technique, you could track the login state and change your application state and do something accordingly (e.g, redirect/render a different view or layout) when the login state changes.
I am developing an app using angularjs and this is my first hands on using angular. Although, I have started understanding it and have developed some part of the app but I am stuck at one particular point.
I am trying to implement login functionality, so as the page loads, I am authenticating user and redirecting him to login page. On successful login, I am storing some values of user in one of the config provider.
Now I am using an API which has their own method of authentication and they have expose the ajax method which I can use to authenticate a user.
I have provided a snippet below. What I am primarily doing is using the external API, authenticating the user and once authenticated, I am getting roles associated to that user using another ajax method of the API, called "GetUserDetails".
And inside the response of the "GetUserDetails", I am injecting a provider and setting some values, so I can use this across my app.
The problem here is the app.config method is never called/executded. I mean the ajax request is returning response, and the alert is displayed on my page, but app.config is never executed.
But the same app.config if I call inside the done() of GetUser method, the app.config gets executed and stores values in my provider. But I want the GetuserDetails values also to be stored before I do anything in my app as I want to execute certain functionality based on user.
Below is my function in main.js file
function(angular,angularRoute,app,routes,configService){
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
$.c.authentication.getUser()
.done(function(response){
if(response.userName!="anonymous"){
$.c.ajax({
method: "GetUserDetails",
parameters: {
User: response.user
}
})
.done(function(res) {
alert("I have reached the destination").
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(true);
configServiceProvider.setUserName(response.userName);
configServiceProvider.setUserObject(response);
configServiceProvider.setUserRoleDetails(res);
}]);
})
.fail(function(res) {
alert("Error while getting user roles ."+res);
});
angular.resumeBootstrap([app['name']]);
}
else
{
app.config(['configServiceProvider', function(configServiceProvider){
configServiceProvider.setLoginStatus(false);
configServiceProvider.setUserName(response.userName);
}]);
//Show Login Screen
var url = window.location.href.split("#")[0];
window.location.href = url + "#/Login";
angular.resumeBootstrap([app['name']]);
}
})
.fail(function(response){
$rootScope.isLoggedIn=false;
});
});
Here is my configServiceProvider
define(['../app'],function(app){
return app.provider('configService', function(){
var options={};
this.setLoginStatus = function(status){
//$rootScope.isLoggedIn = status;
options.isLoggedIn=status;
};
this.setPreLoginInfo=function(info){
options.preLoginInfo=info;
};
this.setUserName=function(name){
options.username=name;
}
this.setUserObject = function(userObject) {
options.userObject = userObject;
}
this.setUserRoleDetails = function(userRoleDetails) {
options.userRoleDetails = userRoleDetails;
}
this.$get=[function(){
if(!options){
}
return options;
}];
});
})
Can anyone please explain me what's going wrong here or what I am missing ?
Also, is there any alternative to achieve the same functionality ?
No luck in figuring out why the above scenario was not working. Since I had already spent lot of time behind this, I have found a workaround to achieve the same with the use of services.
Trying to get Facebook to authenticate my users via a javascript popup. Right now, I have:
<input type="button" value="Connect with Facebook" onclick="window.open('https://graph.facebook.com/oauth/authorize?client_id=XXXXXXXXXXX&redirect_uri=http://example.com/step2&display=popup')" />
But when the user logs in via Facebook, the popup just displays the Facebook.com homepage. I'd like for the popup to authenticate the user and go away so that I can start retrieving user data from the graph api.
Is there a better / easier way to do this? Simple examples are appreciated.
Thank you.
oauth2 in facebook involves two steps, call authorize to get code, then call access_token to get token.
One way to deal with the pop login:
open login url in new window just like you did,when the facebook redirects back to your url in the popup, you set the cookie either through server side code or using javascript to capture url query parameter, when page is loaded in the popup, close the window immediately window.close.
On your main page, after your window.open code, add JavaScript code to detect if popup is closed and capture the cookie:
var signinWin;
$('#FacebookBtn').click(function () {
var pos = screenCenterPos(800, 500);
signinWin = window.open("[URL]", "SignIn", "width=780,height=410,toolbar=0,scrollbars=0,status=0,resizable=0,location=0,menuBar=0,left=" + pos.x + ",top=" + pos.y);
setTimeout(CheckLoginStatus, 2000);
signinWin.focus();
return false;
});
function CheckLoginStatus() {
if (signinWin.closed) {
$('#UserInfo').text($.cookie("some_cookie"));
}
else setTimeout(CheckLoginStatus, 1000);
}
Why not simply...
function authorizeAppInPopup() {
FB.login(function(response) {
if (response.authResponse) {
// User authorized app
} else {
// User cancelled login or did not fully authorize
}
}, {scope: 'publish_stream'});
}
??? : ]
https://developers.facebook.com/docs/reference/javascript/FB.login/
Checkout this article: Create Facebook PopUp Authentication Window using PHP and javascript for customize popup authentication.
It might be a good idea to do both a callback function from the Child window as Avner says as well as a timer that watches for the window to be closed. That way if the Child window is closed without a specific action you can take appropriate action on the Parent window.
**On Child**
// Set oAuthToken from server side when it comes back from authenticating
// and you have the token on the server side.
var oAuthToken = "";
oAuthToken = "--STRING INSERTED BY SERVER SIDE CODE--";
window.opener.pbFromPopup(oAuthToken);
**On Parent :**
function CheckLoginStatus() {
if (authWindow.closed) {
// Handle error if authentication window is closed
// without any action on Allow or Deny
alert("window closed");
//location.href = "errorPage.aspx?error=authwinclosed;
}
else setTimeout(CheckLoginStatus, 1000);
}
function pbFromPopup(token) {
// Function called from child window,
// token is passed back from child
authWindow.close();
// Put token in a hidden form field and submit the form to pass
// it back to the server
$("#authToken").val(token);
$("#form1").submit();
}