User authentication with Angular & PHP - php

I am quite inexperienced when it comes to the topic of server-side user authentication.
I want to use as few PHP code as possible to achieve the following:
A user can log in to my app. If he does so, i will store all of that users information, including the status of being authenticated to an Angular service.
As a user navigates through my app, i need to check whether or not he is logged in. If he ain't, i need to redirect him immediately.
The question
Would it be enough to set up two session variables when the user has been logged in successfully and then doing something like this on every route change, updating my service and handle the result client-side?
public function getLogStatus(){
return
$_SESSION["isLoggedIn"] == "true" &&
$_SESSION['useradr'] == $_SERVER['REMOTE_ADDR'] ?
true : false;
}

Yes it IS enough.
But I suggest this :
public function checkAuth(){
if(!$_SESSION["isLoggedIn"] || $_SESSION['useradr'] !=$_SERVER['REMOTE_ADDR'])
header('location:"thePage.php"');
}
and call it in the first line of every method that you dont want to non-authed visitors can gain .
public function method(){
$this->checkAuth();
...
}

Related

How to bypass usual Laravel authentication process to set a user as logged in

I am building a new Laravel application (v5.4) that will run alongside (installed in the same environment) an existing PHP application that has it's own authentication system. I want the users who have successfully logged in to the existing system to be automatically authenticated in the Laravel app so they can navigate seamlessly between the applications.
My Laravel app has read-only access (through a second db connection) to the existing system's database so it can safely check that the PHP Session matches the session cookie recorded in the database and I can even pull out the user object and hand it to Auth's login() method.
I want to know the best way to put Auth into an authorised state (not guest) and where is the best place to put such code?
Options I've thunked of so far:
Middleware: Check session and call the login() method on Auth from some application-wide middleware?
Extend Illuminate/Auth/SessionGuard.php and override the attempt() method? If so, how do I tell the other parts to use my extended SessionGuard? (I suspect this was not designed to be easily overridden)
Super hacky disgusting way of dynamically setting the user's password to a random hash and then calling Auth/LoginController#login() in the background with a faked request containing that hash as the password field. (I seriously hope this doesn't end up being the most popular answer)
Some other option (?)...
Thanks in advance for your help SO community!
The solution I ran with in the end was creating a middleware that contains this:
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (isSet($_SESSION['intranet_user_id']) && $_SESSION['intranet_user_id']) {
// Log them in manually
$intranet_user_id = $_SESSION['intranet_user_id'];
if (!Auth::guest() && Auth::user()->getId() !== $intranet_user_id ) {
Auth::logout();
}
if (Auth::guest()) {
Auth::login( User::find($intranet_user_id), true);
}
} else {
Auth::logout();
}

How can I properly authenticate a user as an admin in Laravel?

I am attempting to introduce "ghosting" into my application - wherein I can access our app from the POV of a user.
Currently using the loginUsingID function to achieve this, with a protected route only accessible by admins. However, I would also like to display to the admin that they are ghosting a user by displaying a bar across the top of our app.
I was thinking of adding a property to the user is_being_ghosted - setting it as false on logout, false on login, and true on ghostLogin.
But I realize there is a small chance an admin attempts to ghost a user, and it sets that property, and while they are investigating things within the account, the user themselves refreshes their page (they were already authenticated so do not need to login again). In that case they would see this "admin bar" across the top, which clearly I wouldn't want to happen.
Is there an efficient way to achieve what I'm trying to do here? Am I going about this the wrong way?
As jszobody has mentioned. You could rather manage the state inside the session. You secure the /ghost route and then if the original-user-id session is set you display your bar and an unghost link.
public function ghost(Request $request, $id)
{
$request->session()->put('original-user-id', Auth::user()->id);
Auth::loginUsingId($id);
return redirect('/');
}
public function unghost(Request $request)
{
if ($request->session()->has('original-user-id')) {
Auth::loginUsingId($request->session()->pull('original-user-id'));
}
return redirect('/');
}
Update:
The ghost endpoint basically accepts the id that you want to impersonate, typically found through an ajax search input or something similar. Whatever suites your use case.

Restrict operations in restful PHP API

I am creating an AngularJS application with a restful API written in PHP as backend. This is the first time I'm using AngularJS and PHP "together".
Angular is keeping track of the authentication of users using the ngCookies module. Some operations, like deleting stuff, should only be available for users with specific privileges. How can I make sure that "normal" users or users that have not logged in cannot access the deletion operations of the API?
Any ideas are appreciated.
Here is how I do it.
In users DB table I add column named token VARCHAR(36)
Whenever user logs in:
I update lastlogin column
I update that token with MD5($ip.$email.$logindate)
Now I return user object to Angular and angular knows token.
In Angular $http service I add interceptors and before any request is made Authentication header is set. I use basic authentication. I create string $user_id.'::'.$token.
app.factory('authInterceptor', function($rootScope, $q, appConfig, $injector, $cacheFactory) {
function request(config) {
if(angular.isDefined($rootScope.currentUser.id)) {
config.headers.Authorization = 'Basic ' +
window.btoa($rootScope.currentUser.id + ':' +
$rootScope.currentUser.token);
}
return config;
}
function response(response) {
if(angular.isDefined(response.data.code) && parseInt(response.data.code) == 401) {
var UserApi = $injector.get('UserApi');
UserApi.logout();
$cacheFactory.get('$http').removeAll();
UserApi.login(response.data.message)
.catch(function() {
var $state = $injector.get('$state');
$state.go('app.home');
});
}
return response || $q.when(response);
}
return {
request: request,
response: response
};
})
This is my authInterceptor factory that I insert into app
app.config(function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
})
What is happening there I set standard Authentication header for every request if user is authorised.
Then in PHP I get this header. I get user ID and Token separately. Then I use user ID to get user data from DB where I have token and last login date.
Now I can compare token and see if this user is the one who logged in.
But this is not absolutely secure. If anyone get this token, then he can login. That is why IP is used. not only I check the token against one in DB I also check it against IP. I create MD5($ip.$email.$logindate) because I know all that data and check against token that I get from angular. If it was sent from different IP it will not pass through.
You can also see function response in authInterceptor. Whenever I have authentication problem I send back HTTP code 401. Now in response I know that Authentication failed. I logout user and redirect him to homepage of the site.
Now it is very simple to code. You just return what have to be returned, and do not care about none authenticated user.
But there is more. If you need some kind of ACL, then you can design this as you wish. In your class that return particular RESTFull API method you can define $acl property and set name of the group. In the same place where you check for authentication, you can check for ACL too.
Please see my code here it is PHP backend and Angular frontend
https://github.com/Coach-Hub
This is the basic Idea, you can of course build around that.
I am not a php developer. You can not ensure this thing in front-end-side. Below is the sample code we use in NodeJs app, to validate user has valid permission of deletion or not.
router.patch('/:id', auth.hasRole(userEnums.roles.admin), controller.update);
router.post('/create', auth.hasRole(userEnums.roles.admin), controller.create);
//Checks if the user role meets the minimum requirements of the route
function hasRole(roleRequired) {
if (!roleRequired) throw new Error('Required role needs to be set');
return compose()
.use(isAuthenticated())
.use(function meetsRequirements(req, res, next) {
if (req.user.role.indexOf(roleRequired) !== -1) {
next();
}
else {
res.send(403);
}
});
}
Here auth.hasRole is simple method/middleware, which is a curry design pattern. It checks use req and checks that user has valid permission to delete. In case of user don't have admin permission it return back with unautherize error message.
This is for admin and user relation. We also use another strategy at the end to validate user. Suppose we have expose our delete API and anyone can delete it. In that case we have to ensure that active user has to be the owner of the document. In that case first we get the owner id of the document and match it with requested user id. If matches than we delete the document.
BlogPostApiService.destroy(id, _.curry(hasPermission)(req.user))
//hasPermission implementation
function hasPermission(user, blogPost) {
return user && (user.hasRole(UserEnums.roles.admin) || (user._id.toString() == blogPost.author.id.toString()));
}

Global access to variable

After the user has logged in I want to be able to save the userId for later use within the application. The only place in the application I retrieve the username is from the login form, through the login controller. However, that structure in my application is that the only thing that is passed to my master controller from the login controller is HTML.
Of course I could include the userId in a hidden field inside the HTML that's passed back to the master controller, but that seems too hacky.
So, is there a way that I can save a value (in this case the username) so that it's accessible from other classes/namespaces/functions whatever? I have read a bit about 'global', but haven't managed to get it work in my application.
from LoginController.php:
if ($loginView->TriedToLogin()){
$loginUsername = $loginView->GetUserName(); //Retrieved from form
$loginPassword = $loginView->GetPassword();
}
Upon login, you need to store your user token in a session.
See: http://au1.php.net/manual/en/features.sessions.php
Store user when logging in:
$_SESSION['user_id'] = 32; // fetch from your user provider
You can then write a class/function that utilises the session to check their login status and fetch their details when required.
Like so:
function getUserId()
{
return isset($_SESSION['user_id']) ? $_SESSION['user_id'] : false;
}
function isLoggedIn()
{
return isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']);
}
Then use anywhere in your application:
echo isLoggedIn() ? getUserId() : 'Anonymous';
Also, for great information on how to build an MVC framework, check out "Create your own framework... on top of the Symfony2 Components".
How about Sessions?
Session support in PHP consists of a way to preserve certain data
across subsequent accesses.
http://de2.php.net/manual/en/features.sessions.php
If it's only the username you want store, I would go with $_SESSION[].
It's not the most secure in a (shared) hosted environment, but it's so easy to call session_start(); first thing on pages using the stored data.

cakephp custom login conditions

I would like to check, whether user's account is activated while loggin in, but cake's Auth component takes care of the login in a way I don't know how to control. Cake basically uses blank login function and I have no idea how to check value of User.active.
Thanks in advance
The AuthComponent has a property for setting additional conditions just like this, called $userScope.
Just include this line in your beforeFilter() Auth setup block:
$this->Auth->userScope = array('User.active' => true);
Note: the above applies to Cake 1.x. For 2.x use:
$this->Auth->scope = array('User.active' =>true);
Then you can leave your login method blank and the AuthComponent will append this extra condition when authenticating the visitor.
You can see all the additional properties here:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#configuring-authentication-handlers
If you don't include this extra scope, then inactive users will still be able to log in and you'd have to log them out in your login() method after checking.
On your Users controller, or wherever you want to place it (the action that the login form links to):
function login() {
if ($this->Session->read('Auth.User')) {
$active = $this->Auth->user('active');
if ($active) {
//(do stuff)
}
else {
//(do other stuff)
}
}
}
This assumes that there is an "active" column in your User table that contains either true or false (or 1 or 0). $this->Auth->user() allows you to access the current logged in user's data. More information in here: http://book.cakephp.org/view/1264/user

Categories