Im building an login with angularjs and PHP. The problem I have is that the session not seem to have been set.
I have this controller that uses a service when I hit the login button:
Controller:
$scope.doLogin = function() {
loginService.login({username: $scope.username, password: $scope.password});
};
Here is my services:
'use strict';
angular.module('gameApp_services').factory('sessionService', ['$http', function($http) {
return {
set:function(key, value) {
return sessionStorage.setItem(key,value);
},
get:function(key) {
return sessionStorage.getItem(key);
},
destroy:function(key) {
$http.post('lib/destroy_session.php'); //Förstör sessionen
return sessionStorage.removeItem(key);
}
};
}]).factory('loginService', function($http,$location,sessionService) {
return {
login: function(data, scope) {
var $promise = $http.post("lib/action.php", data); //send data to action.php
$promise.then(function(msg) {
var uid = msg.data;
console.log(uid);
if(uid) {
//scope.msgtxt='Correct information';
sessionService.set('sess_id', uid);
$location.path('/game');
} else {
scope.msgtxt='Incorrect information';
$location.path('/firstpage');
}
});
},
logout:function() {
sessionService.destroy('sess_id');
$location.path('/firstpage');
},
islogged:function() {
var $checkSessionServer = $http.post('lib/check_session.php');
return $checkSessionServer;
/*if(sessionService.get('user')) {
return true;
}*/
}
}
});
As you can see, I'm making a call to my backend, where I check the username and password, and set's the session. The uid that is returned, contains the sessionID=1:
public function DoLogin($username, $password)
{
//Kolla så att användarnamn och lösenord är korrekt, returnera true eller false
$get_user = "SELECT id, username,password FROM users WHERE username='".$username."' AND password='".$password."'";
$user_result = mysql_query($get_user)
or die(mysql_error());
if(mysql_num_rows($user_result) == 1)
{
$_SESSION['sess_id'] = mysql_result($user_result, 0);
$_SESSION['sess_user'] = $username;
return $_SESSION['sess_id'];
}
else
{
return false;
}
}
This works, the correct data is returned back as expected, thus, the session id 1.
In my app.js I have code that prevents you from going to the /game page by typing it in the URL:
gameApp.run(function($rootScope, $location, loginService) {
var routespermission=['/game']; //route that require login
$rootScope.$on('$routeChangeStart', function() {
if(routespermission.indexOf($location.path()) !=-1)
{
var connected = loginService.islogged();
connected.then(function(msg) {
console.log(msg);
if(!msg.data) {
$location.path('/');
}
});
}
});
});
As you can see, Im using my loginService here, where I'm refering to islooged in the service. In islogged I make a call to my PHP backend, check_session.php, where I check if the session exists:
<?php
session_start();
if(isset($_SESSION['sess_id'])) {
echo "authentified";
}
?>
This returns an empty string, the session is not set. When I try var_dump($_SESSION), the result is NULL.
How can this be possible, when I set the session in my backend when I log in, and the resulting value is 1?
Are you sure you want to operate session with angular?
Session is store at browser and server,when you start a request by angular,session will be carried by request header automatically, and you can verify it with you php function at backend, so I think you should check your php code to confirm if session store is avaliable or your broswer can store session by cookies or session store
Related
I am developing a website using Laravel and Ajax. I have a problem when I try to return all messages (Messages model) that belong to specific user (User model) using hasMany method.
web.php
Route::get('/test', 'UserController#testFunction');
Route::post('/test', 'UserController#testFunction');
UserController.php
public function testFunction(Request $request) {
if ($request->isMethod('post')) {
$messages = User::find(1)->messages;
return $messages;
} else {
return 'get method';
}
}
User model
class User extends Authenticatable {
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function messages() {
$this->hasMany('App\Message', 'from');
}
}
Message model
class Message extends Model {
protected $fillable = [
'from', 'to', 'content'];
}
Then I have two buttons (just for testing - POST and GET). They are handled by this JavaScript code
window.onload = function() {
// AJAX Setup
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
// Post Method
$('#postMethod').click( function() {
$.post('test', function (data) {
console.log(data);
});
});
// Get Method
$('#getMethod').click(function() {
$.get('test', function(data) {
console.log(data);
});
});
}
Tables in the databse have a structure as shown below:
users table
messages table
When I click on POST button (handled by above javascript code), I receive this error in console: error in console
If I change $messages = User::find(1)->messages; to $messages = User::find(1)->name;, for example, I get the name of the user with ID 1 returned to the console normally.
I assume that something is wrong with messages() function in UserController.php. Maybe 'from' as foreign key? This is just my guess, maybe the error is somewhere else, please take a look yourself.
Here is your fix, you need to call messages like this messages() that will return relationship instance.
public function testFunction(Request $request) {
if ($request->isMethod('post')) {
$messages = User::find(1)->messages();
return $messages;
} else {
return 'get method';
}
}
Hope this helps.
test with /.
Try this
// Post Method
$('#postMethod').click( function() {
$.post('/test', function (data) {
console.log(data);
});
});
// Get Method
$('#getMethod').click(function() {
$.get('/test', function(data) {
console.log(data);
});
});
So, what I'm trying to do here is something simple:
check the role of the loggedUser on each route (with a resolve that sets the user if a token or login credentials are valid on the backend)
redirect to the intended route
if not allowed for a route, redirect to a different route
In my route provider I have something like
$routeProvider
...
.when('/admin', {
templateUrl: 'views/admin/dashboard.html',
controller: 'AdminDashboardCtrl',
resolve: {
checkLoggedUser: check
}
})
...
where ckeck is this function
var check = function($rootScope, $q, AuthService) {
var deferred = $q.defer();
if($rootScope.loggedUser) {
return;
}
console.log('inside resolve check')
AuthService.check().success(function(data) {
$rootScope.loggedUser = data.user;
deferred.resolve(data.user);
});
console.log('finished check')
return deferred.promise;
};
And my AuthService.check() is this function
check: function()
{
var authtoken = StorageService.get('authtoken');
if(!authtoken) {
$location.path('login');
}
console.log('before returning');
return $http.post($rootScope.base + 'auth/authenticate', { 'authtoken': authtoken });
},
In my .run(function I have
$rootScope.$on('$routeChangeSuccess', function() {
setIntendedUrl();
console.log($rootScope.loggedUser);
console.log($location.path());
});
and setIntendedUrl() check for the loggedUser and redirects to the correct page (or, in what I'm trying to accomplish, redirect to a different page if not allowed, for example the loggedUser has role = 1, can visit only the routes /admin, if a user has role = 2, and the requested path is /admin, he has to be redirected to /user)
So after all this code, when the app run this is my log in the console (see in the code where are they called)
inside resolve check app.js:29
before returning authservice.js:24
finished check app.js:36
intended: /admin/agents/create app.js:149 <--- here is where I redirect the user
Object {id: "21", name: "Kyle", surname: "Butler", roleId: "2"...} app.js:167
/admin/agents/create <--- requested path
This is not what I was expecting, so the first three logs are good, the third doesn't wait the promise to be returned (so I don't have a loggedUser) then the AuthService:check() returns the user and it's everything done at this point, the user with role = 2 is in a route that is not allowed to see.
Just to complete the code, this is the setIntendedUrl function
var setIntendedUrl = function() {
intended = $location.path();
console.log('intended: ' + intended)
if(intended !== '/login') {
if($rootScope.loggedUser && $rootScope.loggedUser.roleId === '1' && !/^\/admin*/.test(intended)) {
intended = '/admin';
} else if($rootScope.loggedUser && $rootScope.loggedUser.roleId === '2' && !/^\/manager*/.test(intended)) {
intended = '/manager';
}
StorageService.set('intended', intended);
//$location.path(intended);
}
};
What I am doing wrong? Why the user in the check function is not resolved before the other code is executed?
Can you make use of session/locals storage or $rootScope where you can store the users authorization object with given routes, permission info once user logged in.
Now is route resolve or run() block you can retrieve the user auth object perform authorization action.
e.g.
.run(['sessionService', '$rootScope', '$location', function(sessionService, $rootScope, $location) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
var currentUser = sessionService.get('user_details');
if(next.taskAccess && next.taskAccess != ""){
var hasPerm = $rootScope.getPermission(next.taskAccess);
if(!hasPerm){
$location.path('/unauthorized');
}
}
});
}]);
In my Angular app I created a service:
.factory('Auth', function($http) {
return {
is_authenticated: function() {
return $http.get('/api/users/is_authenticated');
}
}
});
My method in my API backed by Laravel:
public function is_authenticated()
{
if(Auth::check())
{
return Response::json(array('authenticated' => true));
}
return Response::json(array('authenticated' => false));
}
And then in my controller:
Auth.is_authenticated()
.success(function(data) {
$scope.is_authenticated = data.authenticated;
if(data.authenticated)
console.log('yes');
});
When I go to /api/users/is_authenticated I see nothing on the page, however, when I echo Auth::check() there is a 1 on the page.
In my view I have a list with ng-show="is_authenticated" but it's not working.
What am I doing wrong here? I'm failing to see the problem. Why is 'yes' not being logged to the console?
And yes, I have injected the Auth service into my controller.
Here's my initializer:
...
Ember.SimpleAuth.Session.reopen({
currentUser: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return container.lookup('store:main').find('user', userId);
}
}.property('user_id')
});
...
Controller:
isAdmin: function() {
var session = this.get('session.currentUser'),
role = session.get('role'); // 'role' is undefined
return role.get('name') == "Administrator";
}.property()
But when I tried from Templates:
{{session.currentUser.role.name}}
It works perfectly.
How do I access the currentUser to all Controllers or even in Routes?
I think it's because session.currentUser is a promise. Try this in your controller:
isAdmin: function() {
return this.get('session.currentUser').then(function(r) {
return r.get('role.name') == 'Administrator';
});
}.property()
Why don't you add isAdmin to your SimpleAuth Session:
isAdmin: function() {
return #get('current_user.role.name') == 'Administrator';
}.property('current_user')
Then you should be able to do
{{session.isAdmin}}
in your templates.
while login or register save user information in codeigniter session.
then access current login user information form session across the pages.
$userinfo = array(name=>'abc','userid'=>234);
$this->session->set_userdata($userinfo );//use for store user inforamtion
$current = $this->session->userdata('userid'); //for access
echo $current;
I have a problem with my angular app- after a user signs in, if he hits the refresh button, the signin info is lost and the app redirects to the log in page. I found a SO answer for something similar here using $cookieStore but I don't think it can work for me as I'm not using cookies. Can anyone suggest a solution? Here's my authorization service-
var app = angular.module('myApp.services');
app.factory('SignIn', ['$resource', '$q', function($resource, $q) {
var signInUrl = 'https://example.com'
var API = $resource(signInUrl, {}, {
signIn: {
withCredentials: true,
url: signInUrl + '/session',
method: 'POST'
},
signOut: {
url: authApiUrl + '/session',
method: 'DELETE'
},
currentUser: {
url: signInUrl + '/users/#me',
method: 'GET'
}
});
var _currentUser = undefined;
return {
isAuthenticated: function() {
return !!_currentUser;
},
getUser: function(){
var d = $q.defer();
// If _currentUser is undefined then we should get current user
if (_currentUser === undefined) {
API.currentUser(function(userData) {
_currentUser = userData;
d.resolve(userData);
}, function(response) {
if (response.statusCode === 401) {
_currentUser = null;
d.resolve(_currentUser);
} else {
d.reject(response);
}
});
} else {
d.resolve(_currentUser);
}
return d.promise;
},
signIn: function(username, password){
var d = $q.defer();
API.signIn({email: username, password: password}, function(data, headers){
_currentUser = data;
d.resolve(_currentUser);
}, d.reject);
return d.promise;
},
signOut: function(){
var d = $q.defer();
API.signOut(function(){
_currentUser = null;
d.resolve();
}, d.reject);
return d.promise;
}
};
}]);
If you just need to keep track of the _currentUser data past a refresh then you could use sessionStorage within the browser. That extends all the way back to IE 8 and we really shouldn't be supporting any browsers before that anyway.
Usually these things are done with cookies though. When the client first makes a connection to the server (even before the first API call in some cases) a cookie is sent to the client so the server can maintain a session associated with that particular client. That's because the cookie is automatically sent back to the server with each request and the server can check its local session and say, "Oh, I'm talking to this user. Now I can use that additional piece of context to know if I can satisfy their API call or not."
You don't show any of your other API calls here but I'm guessing that you're sending something out of the _currentUser with each API call to identify the user instead? If so, that certainly works, and it avoids the need to synchronize cookies across multiple servers if you're clustering servers, but you're going to have to use something local like sessionStorage or localStorage that won't get dumped like your current in-memory copy of the data does when you refresh the page.