Angular JS + user authentication + page refresh - javascript

So this is my problem.
I can successfully login from my angularJS app using the auth factory i made that communicates to my pp rest API.
lets say Auth.login(user) -> (POST) myapi.com/user/login: the response is the user object that Auth saves locally. Thus Auth.getCurrentUser() returns local user object.
my rest API, i also have a myapi.com/user/get_loggedin_user which returns the current logged in user (using the php session). So if Auth.getCurrentUser should actually check if local user exists, if not do an ajax to myapi.com/user/get_loggedin_user and check if logged in before responding with null. One problem here is, ajax is annoying like this, you would then need to put in a success callback function and have all your code execute inside the success callback.
Now lets say im on the Angular App (website), mydomain.com/user/dashboard (already logged in), and then i refresh my browser. Now, when the page reloads, angular does not know my current user, so before it redirects me to mydomain/login, i want it to check if the user is logged in. i can obviously do a 1 time call within the controller, but is there a more easy way where i can register within a controller with some access restrictions (Eg: logged_in == true), and when you visit any page with logged in requirement, it checks local user (gets the user if does not exist), and redirects to login page if null, or display the page once it matches the requirements?
Different common page requirements: null, logged_in, admin, function: haveAccess(user, object).
NOTE: im using stateProvider

If I understood your question correctly, you are asking about how to check whether the user is logged in before the controller is invoked, and to avoid the check for a logged-in status in each controller that needs it.
If so, you should look into the resolve parameter - this exists both in $routerProvider and $stateProvide.
Essentially you could "resolve" your loggedInUser variable (by doing whatever you need to do via your MyAuth service.
Here's an example of what I mean with $routeProvider:
$routeProvider
.when("/someSecuredContent", {
templateUrl: 'someSecuredContent.html',
controller: 'SecuredController',
resolve: {
loggedInUser: function(MyAuth){
return MyAuth.loggedIn(); // MyAuth.loggedIn() should return a $q promise
}
}
});
Then in the controller, loggedInUser will be injected.
Here's a site with more examples.

Correct me if im wrong:
Do this within the Main Controller (make sure you inject the dependancies like rootScope, state, and your own Authfactory)
$rootScope.$on('$stateChangeStart', function (event, next, toParams) {
if (needToBeLoggedIn()) { //use the next object to read any data, and you can set on the state some flag
event.preventDefault()
MyAuth.loggedIn(function success(){ $state.go(next,toParams); }, function err (){/*send somewhere else*/});
}
})

Put logged_in = true to cookieStore in your login method after authentication as below.
$cookieStore.put('logged_in',true);
$rootScope.logged_in = true;
and in your Controller, do
$rootScope.logged_in = $cookieStore.get('logged_in');
Now you can use this logged_in variable anywhere in the UI to check if the user is logged in.
Make sure to use 'ngCookies' module in your app. and pass the $cookieStore dependency to your controller. You can even keep the user object itself similar to logged_in variable in cookies and retrieve it from cookies.
Make sure to do logged_in = false and clear other variables in cookies and set it to blank in your logout method.

Related

Inertia Manual Share State Lazily Inside Controller not Working

I'm going crazy because of this one, I have this address form in a very nested component and a route to validate the form input data. In the controller, I want to return back to the same page but share the form data to be able to fetch it in a parent component. I'm trying to follow Inertia DOCs to lazily share the data to be available to all components but for some reason this isn't working!
1- I'm submitting the form:
const submitAddressCheck = () => {
shippingDetailsForm.post(
route("cart.checkaddress", [props.webshop_slug]),
{}
);
};
2- The form gets validated as expected but it doesn't share the data globally to all components.
CartController.php
public function checkaddress(StoreAddressCheckRequest $request)
{
Inertia::share(
'testing',
fn ($request) => $request
? $request
: null
);
return redirect()->back();
}
Once I submit the form it gets validated and that's it, no new props passed, the data isn't being shared to my parent component or anything. Am I missing something?
Inertia::share() will not persist any data passed between requests. So if you share data and then redirect to another route, then your shared data will not be passed.
You are probably looking for Flash messages. With flash messages you use the with() method when redirecting to show errors, success messages, anything you like. Make sure you follow the documentation and add the code to the HandleInertiaRequests middleware.
When it is time to redirect, you do something like this:
return redirect()->back()->with('testing', $request->all());

How to call .isNewUser() in authStateObserver in firebase

Its not at all clear in the documentation how to check if a freshly logged in user has logged into my web app previously. There is an isNewUser() call referenced here:
AdditionalUserInfo
What is not clear is how to get access to this call when using a firebase auth call and observer.
firebase.auth().onAuthStateChanged(authStateObserver);
The authStateObserver gets a user object after the person logs in using the provider specified. This user object cannot be used to call .isNewUser() so how does one get to the additionalUserInfo which has the call to .isNewUser() from inside this authStateObserver? This is in javascript in a web app.
firebase.auth().onAuthStateChanged only triggers with the FirebaseUser. You can't get additionalUserInfo or any credential eg. OAuth tokens associated with the result from that observer. You have to get it from the firebase.auth.UserCredential after the sign-in promise resolves.
As these results are only available once on sign-in and Auth does not refresh OAuth credentials or actively update underlying OAuth profiles, Firebase Auth opted not to provide them in onAuthStateChanged listener as it could mislead developers to think that the listener can be used to listen/get new credentials or additional user data when in reality this information is only available once on sign-in.
The observer will only observe changed to the FirebaseUser, eg. sign-in or sign-out events.
For isNewUser(), go into the FirebaseUser class, click on the child class, it should take you to class zzn (for Android & as of now). Search for "isNewUser", you will find a field tagged with that string. It is zzj:
#Field(
id = 10,
getter = "isNewUser"
)
private boolean zzj;
Now search for the getter of that field, in my case it is:
public final boolean zzj() {
return this.zzj;
}
So in your code base, this is the condition: ((zzn) firebaseUser).zzj()
All you have to do is follow the Zzzzz letters. Smh (painful naming).

$dirty property is back to true even after calling $setPristine() in the $scope

I am stuck on something that might sounds a JS asynchronous problem. I am developing an AngularJS application, and when the user types any form data but moves to another page without saving, the app is able to ask whether s/he wants to save it before redirecting to the next page.
But, when the saving is successfully completed, the app is still asking the user whether s/he wants to save it, again (bug), because the conditional statement
if($scope[attrs["name"]].$dirty)
is true even after I call $setPristine in my save() function.
Here it is my directive:
app.directive('formConfirmation', function($modal){
return function($scope, attrs){
$scope.$on('$locationChangeStart', function(event, next, current){
if($scope[attrs["name"]].$dirty){ // the problem happens right here
/* open modal for confirmation */
/* and checks whether the user wants to save the dirty form */
modalInstance.result.then(function(answer){
if(answer){
$scope.save();
}
});
}
});
}
});
And my controller's save function is like this:
$scope.save = function(){
/* calling a service from a factory to save the record... */
utils.save($scope.record, function(data){
// saving was successfully completed
$scope.myForm.$setPristine(); // $dirty value is set to false
$location.path('/main');
}, function(dataError){
// saving has failed
});
}
And my HTML:
<form name="myForm" ng-controller="myCtrl" form-confirmation>
<!-- Form fields here -->
</form>
I imagine the problem happens when I change the path location inside the save function, firing the $locationChangeStart event once again. However when I check the $dirty property of my form the second time, its value is back to true even after calling $setPristine in my save() function.
I am not sure what is happening, I am learning js and angularJS, but this asynchronous javascript architecture is always a challenge. Any help, or guidance would be appreciated.

Is there a way in firebase to get if email is verified?

For now I'm doing like this:
firebase.auth().onAuthStateChanged((user) => {
if (!user.emailVerified) {
//Something
}
});
But, the problem is I have added this block of code in multiple pages and whenever the authentication changed (user logged in or logged out) It calls all those functions and that effects other code!
So, is there any way by which we get if users email is verified or not - without using 'onAuthStateChanged()'
Anywhere in your page you can do:
firebase.auth().currentUser.emailVerified
To determine the current state. You only need onAuthStateChanged() to monitor when the state changes.
listener
onIdTokenChanged
to reload
auth.currentUser.reload()
auth.currentUser.getIdToken(true)

Updating AngularJS View when user action has completed

I'm writing some small exercises to teach myself AngularJS and I'm trying to write some simple user Authorisation tasks. I have a form to collect/input a username and password, these are then sent to a rest service using $http and CORS (as my REST service is running on a different port), they are checked and if there is a match I return a UUID and create a token and I $broadcast a loggedIn value to true that is on the $rootScope, something like this.
// this is in a service I call 'authService'
this.login = function (user) {
return $http({method: 'POST', url: 'http://127.0.0.1:3000/login', data: user})
.then(function (response) {
// set up a local storage token
storageService.setLocalStorage('token', response.data[0].uuid);
// broadCast is loggedIn - we have a match
$rootScope.loggedInUser = true; // this is set to false at the .run() of the app
$rootScope.$broadcast('LoggedIn');
return 1;
}, function () {
// return http code later
return 0;
});
};
this.getLoggedIn = function () {
return $rootScope.loggedInUser;
};
Now in a separate menu view I have the following condition (the authService is added as a dependancy on the menu controller):
<div id="logIn" ng-show="!authService.getLoggedIn()">...</div>
Now when I load the app for the first time the condition is correct, however I want this condition to update should a user log in correctly (so the div) isn't shown. In the menu controller I have the following code, none of it seems to do anything?
$scope.$on('LoggedIn', function () {
authService.getLoggedIn(); // doesn't update the view?
console.log($rootScope.loggedInUser); // returns true
console.log(authService.getLoggedIn()); // returns true
});
$scope.$watch('loggedInUser', function () {
console.log('loggedInUser has changed ' + $rootScope.loggedInUser);
// This runs once when we set $rootScope.loggedInUser in the .run() of the app, output is: 'loggedInUser has changed false'
// then when we have successfully logged in again, output is 'loggedInUser has changed true'
});
Okay, so the condition on the <div> in my menu view doesn't update when I changed the $rootScope.loggedInUser, I'm doing something wrong in my approach, can someone give me some advice or correct my approach to this. Thanks
You don't have to do anything special in Angular to update view when some prop is updated, provided it is in the correct scope. I provided a Plunkr for you which demonstrates that you don't have to do anything special to refresh the view.
http://plnkr.co/edit/B6kUwJdA4lRKkjAItSFO?p=preview
You don't have to do watches, you don't have to do anything. That is the power of Angular. Also, it is weird that you set stuff in rootscope. My advice for you is to look at my example and revise/restructure your code. Also, having stuff like this:
ng-show="!authService.getLoggedIn()"
Is not the recommended way of doing things. You can have a controller, in which you say:
$scope.userLoggedIn = autService.getLoggedIn();
and then in your view:
ng-show="userLoggedIn"
You can also take a look at this plunkr:
http://plnkr.co/edit/aRhS0h7BgpJJeRNvnosQ?p=preview

Categories