Making a logged in user-variable in AngularJS+laravel - angularjs

I'm trying to make a global variable called theUser which contains the userinfo if logged in.
I have tried putting this in my SPA php file:
app.value('theUser', '<?php echo Auth::user(); ?>');
And it works but only after refreshing page. (Login happens via angularjs logic + a $http request to auth/login which returns userinfo if logged in)
In my angular auth app, I have done this:
var login = $http.post("auth/login", sanitizeCredentials(credentials)).success(function(data) {
theUser = data;
$rootScope.theUser = theUser;
});
And that works, but only when the user logs in. If I refresh, theUser is empty. And I can't get these two solutions to work together. I probably need another approach.
All I want is an user variable that I can access from anywhere in my app,
which is set if the user logs in, or have been logged in before. Using Laravel 5.1.
Here is my auth app service js: http://pastebin.com/HcdLaZcD
How can I make this work?

Why dont you use PHP-Vars-To-Js-Transformer by Laracasts. Then whenever a User logs in, you could set a Session variable auth_user and then get that variable to JavaScript as shown below (in your Laravel AuthController#login):
...
\Session::put('auth_user', \Auth::user());
JavaScript::put([
'theUser' => \Session::get('auth_user')
]);
...
And when the User logs out: \Session::forget('auth_user');
theUser variable will be available anywhere in your JavaScript (or you can Namespace it also, check the Github link above).

on top of the page under script tag
window.user = <?php echo Auth::user(); ?>
and
app.value('theUser',window.user);
app.run(function ($rootScope, theUser) {
$rootScope.theUser = theUser;
});

For accessing the logged in user from your JavaScript files, you may try something like this (Create a view composer, also layouts.master dictates layouts/master.blade.php):
View::composer('layouts.master', function($view) {
$user = null;
if(Auth::check()) {
$user = Auth::user();
}
$view->with('authUser', $user);
});
In the master layout try this (So User variable will be available as JS object if the user is logged in):
<head>
<script>var User = {{ $authUser or 'undefined' }}</script>
</head>
This is just an idea, implement it according to your need. Also, you may use a namespace like App.user. I wrote an article about this lasr year, you may
check it here. Btw, it was for Laravel 4.x.
.

We have made use of html5 local storage to overcome this once the user is logged in, you just put the user's info on html5's local storage (works on all browsers, even mobile).
It has some drawbacks which you have to overcome, and also have some control on your routes filters to avoid someone loading page they shouldn't be allowed to see.
But I'm afraid my answer applies better to our solution and I don't think this answer is perfect but might guide you in a better solution. Our app publishes an API for angular's use and this angular is somewhat empowered with some extensions to ease routing.

Related

window.open("url","_self") works well on localhost url, but not when I put it on a server

I have an angularJS frontend that I redirect to a third party payment gateway when a customer clicks on the Pay button.
I am currently using the following function to redirect to the payment gateway:
if(status.data.result == "true"){
var ref = window.open(url,'_self');
}
};
This code works well when I try it on localhost. But does not work when I put it on the ubuntu server.
Any ideas on why?
Regards,
Galeej
Try adding return false after var ref = window.open(url,'_self'); like
var ref = window.open(url,'_self');
return false;
return false will prevent from page submit and it may work this way to properly redirect on the same page.
May be your content security policy is blocking this url to load.
You can try using _blank instead of _self to see if that is the case.
Also it would be better to use $window, because angular.
Also are you using the fully qualified URL ?
The solution that worked for us was using window.location = url

Session Handling in Angular JS, with Spring MVC

I am creating a project in AngularJs at frontend and Spring MVC in backend.
Now assume when a used logged in and if he wants to update his information, for this i have created an api which request for emailid and update the rest object in database of that email id
Now i have some questions,
1.) I dont want to use CookieStore or others sessionStorage or localstorage (because of my personal vulnerability experience and also i want to use session only) in Angular, how can i do it in angular with Spring MVC.
2.) How can i retrieve the email id from session to update data?
3.)If a user goes to another page how can i maintain that session in another page, how can i check that session is there and user is authentic to see the page
Read a lot about it but unable to find the exact solution with session. Answer over there is manage it by cookieStore.or localstorage, Please help
Let's try and see what is happening here using cookies is the right way to this, you may think it is not safe but is the safest way to do it. With cookies you will be sharing the same session in all tabs, so you can handle in all tabs and share it.
There is also an alternative option and is using URL rewriting, quoting #vanje in this question in stackoverflow
the session is only identified via a URL parameter containing the session ID. So every internal URL of your web application has to be enhanced with this parameter using the method HttpServletResponse.encodeURL(). If you are using a web framework like Wicket, chances are good that this is already done for you.
Lets go now with the Angular JS - Spring MVC approach:
There is no need to access the session within the Angular JS front-end, if you need to use it and you are using JSP you may use scriplet to retrieve the information openening a <%= session.getAttribute("user") %> , but as I said there is no need to do this. You may call your function, and retrieve this information in your controller in Spring.
You have a controller in angular JS that calls with http to your REST controller in Spring such like this. assuming that you save your user first in session:
$scope.getUserInfo= function () {
$http.get(appContextPath +'/rest/getuser/').success(function (data) {
$scope.user= data;
});
};
You may have a request mapping for the URL above:
#RequestMapping(value = "/rest/getuser", method = RequestMethod.GET)
#ResponseBody
public User getUserInfo (HttpSession session) {
User nUser = session.getAttribute("user");
return nUser;
}
I think the best way is to create a method in your AngularJS controller and then call it.
Java code:
#RequestMapping(value = "/menu/get", method = RequestMethod.GET, headers="Accept=*/*")
public #ResponseBody Empleado showMenu(HttpSession session) {
Empleado empleado = (Empleado) session.getAttribute("empleado");
return empleado;
}
AngularJS code:
angular.module('myModule')
.controller('myMenuController', ['$scope', '$http'
function($scope, $http){
getEmpleadoInfo = function () {
$http.get(myContextPage + '/menu/get')
.then(function(data) {
$scope.empleado = data;
})
}
getEmpleadoInfo();
}]);
This way, when you load the page, the object will be loaded on the scope.

AngularJS: How to login once and do not need to login again

I have implemented the authentication/authorization using AngularJS, Jersey REST and Spring Security. After logged in, call the following "create" method to store the user information:
.factory('Session', function () {
this.create = function (user) {
this.id = user.sessionId;
this.username = user.username;
this.userRoles = user.roles;
};
... ...
return this;
})
But, the problem is, every time I do one of the following 2 things, the stored information is lost and I have to login again:
Reload the whole page by pressing F5 or reload icon of browser
OR
Access the same URL from browser address bar
Could you please help me on how to reserve this information to guarantee login only once?
Thanks,
Check out sessionStorage. Not sure what the rest of your code looks like, but presumably your controller could save the Session created by your factory into sessionStorage.

CakePHP reverse routing issues

I've been using routing with "slug" as a named parameter, for example:
Router::connect('/category/:slug', array('controller'=>'categories', 'action'=>'view'), array('pass'=>array('slug'), 'slug'=>'[a-z0-9\-]+'));
I've now stumbled across a problem because I want to restrict the above route to logged in users only, so I've put this in the beforeFilter() function of my CategoriesController:
if(!$this->Auth->loggedIn()) {
$this->Auth->deny('view');
}
Now if I go to /category/my-category (while logged out) I'll be redirected to my application's login page, unfortunately after I log in I'm redirected to /categories/view/my-category/slug:my-category
This is due to line 317 of AuthComponent.php, where we have:
$this->Session->write('Auth.redirect', Router::reverse($request));
So it seems when I do Router::reverse($request) on the above route it doesn't work properly (because it thinks "my-category" should be both a passed and a named parameter).
Is this a problem with the way I've set up this route, or is it a bug with CakePHP? Surely Router::reverse($request) should always return the URL we're currently at?
Any advice appreciated...
I'm not 100% sure if it is a bug or not, but until we find out a work-around could be to manually set the new loginRedirect in your category controller like so:
if(!$this->Auth->loggedIn()) {
$this->Auth->deny('view');
$this->Auth->loginRedirect = '/categories/' . $this->request->params['slug'];
}
Note, check that $this->request->params['slug'] is the right var to use, not 100% off the top of my head.

Redirect to maintenance page in CakePHP doesn't work

I am trying to set a maintenance page so that when the site is disabled, it should appear no matter what page was requested.
I currently tried doing this with $this->cakeError():
in app_controller.php:
function beforeFilter(){
....
if($this->__get_config('maintenance_status') == 1){
$this->cakeError('maintenance', array('message' => $this->__get_config('maintenance_message')));
}
....
}
and in app_error.php:
function maintenance($message){
$this->controller->set('message', $message['message']);
($this->controller->RequestHandler->isAjax()) ? $this->_outputMessage('ajax_maintenance') : $this->_outputMessage('maintenance');
}
The problem is that a Fatal Error occurs, which says: Call to a member function isAjax() on a non-object. But I have obviously set the RequestHandler Component in app_controller.php. Moreover, I have tried calling this error from within another controller and it doesn't give me any Fatal Error.
What could be the problem? Why doesn't it recognize that I have initalized the Component?
From the CakePHP book:
Calling this method will show an error page to the user and halt any further processing in your application
I am assuming that you're calling the error in some callback in AppController.
If that is the case you may very likely be halting execution of your script before your components are instantiated. This would certainly cause your error.
Now, I think this error is a good chance to reevaluate how you're dealing with the problem. Is this really an error? You know the maintenance status is set so it's expected that the user be shown this page. It isn't an error. Furthermore, you certainly wouldn't want 10,000 messages in your log telling you that you turned maintenance on!
I think this could be better solved by utilizing some controller callbacks and a little bit of code.
I don't know what _get_config() is so I assume it is a custom user function that you can call in this callback.
We'll be using the beforeFilter() controller callback.
class AppController extends Controller {
public function beforeFilter() {
if ($this->_get_config('maintenance_status') === 1) {
$this->redirect('/maintenance');
}
}
}
Now, you can just setup a maintenance controller, attached to its own view, that will properly show your maintenance message, and won't log all those connection attempts during maintenance in your error log.
Slightly better would also be to use the Configure::read( "System.maintenance" ) or similar. (I tend to namespace my config data, System being the namespace for stuff like maintenance flags etc.)
Also, as Charles said - don't use an error page for an expected event. Errors are to show the user, and for the application to handle notifications etc, about unexpected failures. The maintenance page could simply be a view file in the /app/views/pages/ folder. Redirect to that if the config key is set to true/1.
Your approach seems to be intelligent, but you might be overdoing it a little.
I have a similar setup in a site I am currently developing and I simply use the auth component to take care of it for me.
To help out, I setup a new offline layout that I force the application to use if status of the site is 0 (offline). If the status is 0 app_controller denies access to the entire site.
$this->Auth->deny('*');
$this->layout = "offline";
Also, in this layout I have a hidden login form that appears if the user clicks the message.If user is able to authenticate (all users for now - development) access is granted to the entire site using the default template.
Check it out, it might help you out...
Click Here
Some of the code, but you can read more about it in the link above
function beforeFilter(){
// Site Offline = 0 , Site Online = 1
if($this->Configuration->get_site_status() == 1){
// Allow access to the site to all users and perform all required
// beforeFilter code
}else{
...
// If site is OFFLINE but User is logged in allow access.
// Later I will need to change it to only allow admin access if logged in as I am still developing
// Everyone else will be denied access even if they are able to authenticate
if(!$this->Auth->user() == null){
$this->layout = 'default';
$this->Auth->allow('*');
}else{
$this->layout = 'offline';
$this->Auth->deny('*');
}
...
}
}

Resources