What would be the best way to work with sessions CodeIgniter to do the following ?
I have users with a role and a company that are stored in a database.
I want identify user role and company without do :
if($roles == 'Editor'):
// do something
endif;
In each controller or method.
Example :
If users is logged a function in header checks that and if not it redirects to the homepage.
Have you considered using an authentication library? Tank Auth is a good solution and if you need roles you can try the Tank Auth with Roles library.
Also, if you want to check if a user is logged in you can add the code to the constructor of your controller.
function __construct() {
// Check the user is logged in / roles / etc
if( ! $roles == 'Editor' ) { redirect('welcome'); }
}
Just add this code inside the class and it will run for any page within that controller.
Related
I am currently in the process of trying to understand how Laravel functions. And my biggest question is the authentication process. Lets say i have an admin panel and a user panel. I have a column in the "users" table for "user_type" and 1 = normal user and 2 = admin user. When a user logs into the user login form laravel checks the users info and makes sure that the type is 1 for a normal user login. If it is, it sets a session. But how do i check if the user logged is a admin or normal user. Any help is appreciated greatly! :D
First in your web.php you can do this:
Route::post('/login', 'Auth\LoginController#determineLoginType')->middleware('guest');
And in your LoginController.php you can do something like this:
public function determineLoginType(Request $request)
{
/**
* Here I am assuming that the email field on your user model is unique,
* therefore I am retrieving that specific user by the email they provided
* at the login form
*/
$user = \App\User::where('email', $request->email)->first();
if ($user && $user->user_type == 2) { // Check if the user exists & check their type.
return redirect('/admin-dashboard'); // If they're an admin redirect them to the admin dashboard.
}
return redirect('/home');
// Otherwise proceed normally and redirect the user to the normal home or dashboard.
}
Of course you should extends this to include what if they user provided an invalid email, so you should redirect them back with the input and errors for example, hopefully this is similar to what you're looking for.
You can simply do:
if (auth()->user()->user_type == 2) {
// Do admin stuff
}
Otherwise you can add a function in your User.php
public function getIsAdminAttribute()
{
return $this->user_type == 2;
}
Then you can do the following:
if (auth()->user()->is_admin) {
// Do admin stuff
}
Building an app in Laravel 5.3, one of the functionalities is for the admin to be able to log into the app as a user, to be able to see what that specific user can see, while maintaining his admin session to be able to go back to the user list and be possible to log in as another user without having to re-authenticate.
Currently implemented the basic out-of-the-box Laravel Auth, meaning if I start another auth session it will terminate my admin session making me having to re-login.
I have checked Laravel Multi Auth but seems to work with two tables (user,admin), which in my case we use one user table and use an ACL for managing roles and deciding whos admin and whos user.
What programming logic ideas do you guys have for this solution? Trying to find other opinions/ideas in how this could be implemented in Laravel 5.x
I've implemented the feature on a project recently. I did this using the session and a middleware. This is how I did it:
Create a controller 'ImpersonateController' and Set two routes for impersonateIn and impersonateOut for the purpose.
Route::get('impersonateIn/{user}', 'ImpersonateController#impersonateIn');
Route::get('impersonateOut', 'ImpersonateController#impersonateOut');
In the ImpersonateController#impersonateIn method just set the user id you want to log in and the URL backUrl into the session variable.
public function impersonateIn($id)
{
session(['impersonated' => $id, 'backUrl' => \URL::previous()]);
return redirect()->to('dashboard');
}
public function impersonateOut()
{
$back_url = Request::session()->get('backUrl');
Request::session()->forget('impersonated', 'secretUrl');
return $back_url ?
redirect()->to($back_url) :
redirect()->to('dashboard');
}
The first part is done. Now every request need to check the if the session has the
impersonated variable set. A good place to do that is a middleware.
Create a middleware to check the session on the handle method. If the impersonated found then log as the user using the Auth::onceUsingId() for the current request only.
class ImpersonateMiddleware
{
public function handle($request, Closure $next)
{
if(Request::session()->has('impersonated'))
{
Auth::onceUsingId(Request::session()->get('impersonated'));
}
}
}
Now you just need to apply the middleware for every request. The best place to do this from the Http/Kernel.php
protected $middlewareGroups = [
'web' => [
//....
\App\Http\Middleware\ImpersonateMiddleware::class,
],
];
The only remaining thing is you need to check the session and replace the logout route to the impersonateOut. Now when the admin logged out from the user will be redirected to the old route.
That's it!
Are you sure you really have to login?
I would stay logged in as admin and simulate user login.
You can allow admin access to all the databases.
In your controller you can use User::find($user_id) instead of Auth::user() for accessing user's data.
https://laravel.com/docs/5.3/database
https://laravel.com/docs/5.3/eloquent
Personaly, I would do this with sessions. I have not used Laravel but I use PHP often, so my answer will be in PHP.
In the header page, you most likely have some kind of session check to see if the user is logged in. For example:
<? php
session_start();
if (isset($_SESSION['user'])){
//do stuff with the user session
} else {
die('User not logged in!');
}
?>
I would change this to something like:
<? php
session_start();
if (isset($_SESSION['fakeuser'])){
//do stuff with the user session
//change logout button to destroy this session instead of logging the user out
}
elseif (isset($_SESSION['user'])){
//do stuff with the user session
} else {
die('User not logged in!');
}
?>
In the page in which you swap users, you would just simply copy the way a session starts when a user logs in. To switch users, you destroy the new 'fakeuser' and you are back to your old session + admin permissions without having to log back in again.
That's the logical approach I would take anyways.
i have built upon this tutorial http://www.jamesfairhurst.co.uk/posts/view/creating_an_admin_section_with_cakephp_updated
and currently have a functional and quite well fleshed out admin section for my application.
Due to poor foresight I haven't taken into account regular users who need to be able to login to their own home page, where they can view bookings etc.
I have an appropriate database set up and have included a 'roles' field for authentication. I have also followed cakePHP's own 'auth' examples however have failed to get them to implement without throwing various errors, at this stage i'm not wanting to go changing the structure of the login system too much, that kind of thing can become a headache quick!!
I have spoken to the original author of the tutorial and he agrees that some simple logic added to the user_controller.php file should suffice.
basically i need something along the lines of an: "if user == 'user' THEN redirect to 'user_index.php' put simply.
below is the current LOGIN function for user_controller.php
function login() {
if(!empty($this->data)) {
// unset unrequired validation rules
unset($this->User->validate['username']['check_username_exists']);
// validate form
$this->User->set($this->data);
if($this->User->validates()) {
// update Last Login date
$this->User->id = $this->User->_user['User']['id'];
$this->User->saveField('last_login',date("Y-m-d H:i:s"));
// save User to Session and redirect
$this->Session->write('User', $this->User->_user);
$this->Session->setFlash('You have successfully logged in.','default',array('class'=>'flash_good'));
$this->redirect(array('action'=>'index','admin'=>TRUE));
}
}
}
All validation is handled in the user.php model and there is some logic in app_controller.php to redirect authentication, it is included below;
app_controller.php
class AppController extends Controller {
// class variables
var $_User = array();
/**
* Before any Controller action
*/
function beforeFilter() {
// if admin url requested
if(isset($this->params['admin']) && $this->params['admin']) {
// check user is logged in
if( !$this->Session->check('User') ) {
$this->Session->setFlash('You must be logged in for that action.','flash_bad');
$this->redirect('/login');
}
// save user data
$this->_User = $this->Session->read('User');
$this->set('user',$this->_User);
// change layout
$this->layout = 'admin';
}
}
}
I faced a similar problem in my application. In my User model, I created a getRole() method which just pulled the role out of the database, and then I used a switch statement to redirect users to the correct controller.
As a different approach, you could just add in an isAdmin column (default 0, 1 would indicate an admin) to your users table. Assuming there are not too many admins already, you could just manually set the admins. In your controller you would just need to check the field and the redirect accordingly.
I've to make a cakePhp authentification, and I wish to use the "Auth" component. I'm trying to see if it fill my requirement:
I need to authenticate users with their email OR their customerId, (with an addition password of course). I can't find if it is possible to have two fields(or more) on which the authentication can be done
I've several parts on which I need to be authenticated. But I need differents granularity:
For some things, it's the whole controller which should not be accessible(if possible with exception(e.g. all the "User" controller, except the login/register action) for other I really need that it's the whole controller(e.g. the cart controller)
Sometimes I need that only some actions are unavailable without being logged
Sometimes I need that only a part of the view isn't displayed(e.g. login element not displayed)
Does the component manage action like password change? Because if the user change its password I need that he did not get disconnected.
Thank you very much for your help
The short answer is that yes, you can do these things, but it seems to me that the ACL might be overkill for your needs (but I also tend to avoid the ACL if there's any opening at all to do so). To your points:
As Ivo suggests, you'll need a custom UsersController::login() method to authenticate by multiple fields (If your auth model isn't User, then use the appropriate controller). If the Auth component's login method fails, it passes control to your custom login() method. Here's a snippet from a project I've been working on:
function login() {
# Allow login by either username (legacy) or email.
# If no authenticated user exists at this point then the Auth
# component's login() method has failed and control has been passed
# here for any further handling. Since the expected credentials
# (email and password) have failed we're going to check for
# username and password.
$user = $this->Auth->user();
if( empty( $user ) && !empty( $this->Auth->data['User']['email'] ) && !empty( $this->Auth->data['User']['password'] ) ) {
$user = $this->User->find(
'first',
array(
'recursive' => -1,
'conditions' => array(
'User.username' => $this->Auth->data['User']['email'],
'User.password' => $this->Auth->data['User']['password'],
)
)
);
if( empty( $user ) || !$this->Auth->login( $user ) ) {
# Set the configured flash message b/c login failed after both checks.
$this->Session->setFlash( $this->Auth->loginError, null, array(), 'auth' );
}
}
$this->redirect( $this->Auth->redirect(), null, true );
}
For action access, just use the $this->Auth->allow() and $this->Auth->deny() methods in each relevant controller's beforeFilter() callback. For example, in the UsersController, you may want to do something like this:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->deny('*');
$this->Auth->allow( 'login', 'logout' );
}
In views, just determine whether the user is authenticated by testing the Auth.User value to determine what to display/hide from anonymous/authenticated:
if( $this->Session->check( 'Auth.User' ) ) { ... }
If the password changes, you can re-authenticate the user transparently by calling $this->Auth->login( $user_data ). I do this, for example, when a user registers. I don't want him/her to have to then go login, so I just login automatically.
Auth doesn't do exactly what you want out of the box. It can only handle whether a user authentification is required to access an action or not. Once the user is logged in, Auth does not care about the user's level access anymore.
If you wish to use more than two fields, I suggest that you extend the AuthComponent and rewrite the login method to fit your needs. I never did it but I imagine that it is reasonably easy.
Regarding your access levels, I would use ACL that can manage access to actions of all the controllers. Once set up, you will have to manually set the permissions for each actions, either using one of the plugins written by the community or manually.
If you wish to disable part of your views you will need to read the permissions to test the user's access level from there. A good thing would be to save the permissions in a cache file or in the session as the user logs in to make it avaiable in the view. Then write your tests and echo what's needed.
(I am using CakePHP 2.0, I don't know how easily you can extend AuthComponent in 1.3 if you're using it)
With Auth, you need to have exactly 2 fields (that you can specify) to authenticate on. One field (password) will be hashed. Yes, all levels of access you want can be specified in Auth: http://book.cakephp.org/view/1251/Setting-Auth-Component-Variables
You'll have to manage the password change, but the users won't get logged out if they change password.
Sometimes I need that only a part of the view isn't displayed(e.g. login element not displayed)
wut?
Create a custom login() which tries to authenticate through either method.
You can also setup the Authenticate variable to do a custom login.
You can specify in different controllers what parts Auth should be allowing to authenticated users. See Auth methods.
You can also use ACL (see the full Cake ACL tutorial, etc) to control granular permissions.
Sometimes I need that only a part of the view isn't displayed
Create an element which checks for Auth->user() to select what content to display.
For the Allow and Deny part can be easily done with the Auth Component.
use something like
$this->allow('*'); // to allow every thing
$this->deny('*'); // to deny every thing
$this->allow('login', 'signup'); // allows login and sign up without being logged in
$this->deny('profile', 'password'); // need to be logged into to access profile and password and rest of the actions are allowed.
For the change of password you can save the changed password to the database and force logout the user and redirect him to login again
$this->Auth->logout(); this forces the user to logout of cakephp Auth
For the first question - loggin in using email or customer id is not directly possible using cakephp Auth component as you will have to define in particular which of them acts as a username.
Alternative solution is you can just copy the Auth Component into your app/controller/component and hack the code.
When you receive the user name you can test it against email and customer id and maintain the flow.
Hope this helps
I'm running Kohana 3, and having a hard time understanding the Auth module, or even if it's what I need. Basically I want to create a basic user profile site with basic username/password protection.
How do I take my existing controllers...
class Controller_Profile extends Controller
{
function action_index( $user_id )
{
// User should already be authenticated by here I think
}
}
...and use them with some sort of authentication system
For Kohana 3 you'll want to do your check in before and not __construct like JIStone suggests.
public function before()
{
parent::before();
// This automatically checks for an auto login cookie (thanks kemo).
if ( ! Auth::instance()->logged_in())
{
// Redirect to a login page (or somewhere else).
$this->request->redirect('');
}
}
Simple enough to understand. You can put this into a controller and have all the controllers that need authentication to extend that.
If you will be requiring a user to be registered for all pages on the controller you can put a check in your __construct() statement:
function __construct()
{
//Check roles for Access!!!!
parent::__construct();
$this->load_user();
if( ! $this->is_registered )
{
if(request::is_ajax())
die('This ajax call cannot be completed due to permission issues.');
// this will redirect from the login page back to this page
$this->session->set('requested_url', url::current());
url::redirect('user/login');
}
}
This is the code we use, but it is Kohana 2, not 3, so you will need to adjust a bit for your purposes.
I have provided a link to a short walkthrough for the installation and basic usage of the Auth Module in Kohana 3
Once you have your Auth process working, you can protect certain controllers by checking for a logged in user and proper authentication role in your before() method, or create a base controller for all your controllers that will need this check. If the user is not logged in, redirect them to the login page, if they do not have the proper access level (or role), then you can show them an "Access Denied" page.