Redirect to a page based on user roles in codeigni

2019-08-28 22:03发布

问题:

Am working on a user login authentication with codeigniter.

The login script works great. My question is, when a user is logged in I want the user to be redirected to a page based on his user roles

Roles are as below subscriber, admin, client, postman

User_model.php is as below

class User_model extends CI_Model {

    public $status;
    public $roles;

    function __construct(){
        // Call the Model constructor
        parent::__construct();
        $this->status = $this->config->item('status');
        $this->roles = $this->config->item('roles');
    }

    public function insertUser($d)
    {
            $string = array(
                'firstname'=>$d['firstname'],
                'lastname'=>$d['lastname'],
                'phonenumber'=>$d['phonenumber'],
                'email'=>$d['email'],
                'roles'=>$this->roles[1],
                'status'=>$this->status[1],
                'password'=> '',
                'last_login'=> '',
                'created_at'=> '',
                'updated_at'=> ''
            );
            $q = $this->db->insert_string('users',$string);
            $this->db->query($q);
            return $this->db->insert_id();
    }

    public function isDuplicate($email)
    {
        $this->db->get_where('users', array('email' => $email), 1);
        return $this->db->affected_rows() > 0 ? TRUE : FALSE;
    }

    public function insertToken($user_id)
    {
        $token = substr(sha1(rand()), 0, 30);
        $date = date('Y-m-d');

        $string = array(
                'token'=> $token,
                'user_id'=>$user_id,
                'created'=>$date
            );
        $query = $this->db->insert_string('tokens',$string);
        $this->db->query($query);
        return $token . $user_id;

    }

    public function isTokenValid($token)
    {
       $tkn = substr($token,0,30);
       $uid = substr($token,30);

        $q = $this->db->get_where('tokens', array(
            'tokens.token' => $tkn,
            'tokens.user_id' => $uid), 1);

        if($this->db->affected_rows() > 0){
            $row = $q->row();

            $created = $row->created;
            $createdTS = strtotime($created);
            $today = date('Y-m-d');
            $todayTS = strtotime($today);

            if($createdTS != $todayTS){
                return false;
            }

            $user_info = $this->getUserInfo($row->user_id);
            return $user_info;

        }else{
            return false;
        }

    }

    public function getUserInfo($id)
    {
        $q = $this->db->get_where('users', array('id' => $id), 1);
        if($this->db->affected_rows() > 0){
            $row = $q->row();
            return $row;
        }else{
            error_log('no user found getUserInfo('.$id.')');
            return false;
        }
    }

    public function updateUserInfo($post)
    {
        $data = array(
               'password' => $post['password'],
               'last_login' => date('Y-m-d h:i:s A'),
               'created_at' => date('Y-m-d h:i:s A'),
               'updated_at' => date('Y-m-d h:i:s A'),
               'status' => $this->status[1]
            );
        $this->db->where('id', $post['user_id']);
        $this->db->update('users', $data);
        $success = $this->db->affected_rows();

        if(!$success){
            error_log('Unable to updateUserInfo('.$post['user_id'].')');
            return false;
        }

        $user_info = $this->getUserInfo($post['user_id']);
        return $user_info;
    }

    public function checkLogin($post)
    {
        $this->load->library('password');
        $this->db->select('*');
        $this->db->where('email', $post['email']);
        $query = $this->db->get('users');
        $userInfo = $query->row();

        if(!$this->password->validate_password($post['password'], $userInfo->password)){
            error_log('Unsuccessful login attempt('.$post['email'].')');
            return false;
        }

        $this->updateLoginTime($userInfo->id);

        unset($userInfo->password);
        return $userInfo;
    }

}

The main code for controller is as seen below

defined('BASEPATH') OR exit('No direct script access allowed');

class Main extends CI_Controller {

        public $status;
        public $roles;

        function __construct(){
            parent::__construct();
            $this->load->model('User_model', 'user_model', TRUE);
            $this->load->library('form_validation');
            $this->form_validation->set_error_delimiters('<div class="error">', '</div>');
            $this->status = $this->config->item('status');
            $this->roles = $this->config->item('roles');
        }

    public function index()
    {

            if(empty($this->session->userdata['email'])){
                redirect(site_url().'main/login/');
            }

            /*front page*/
            $data = $this->session->userdata;
            $this->load->view('header');
            $this->load->view('index', $data);
            $this->load->view('footer');
    }



        public function login()
        {

            $this->form_validation->set_rules('email', 'Email', 'required|valid_email');
            $this->form_validation->set_rules('password', 'Password', 'required');

            if($this->form_validation->run() == FALSE) {
                $this->load->view('header');
                $this->load->view('login');
                $this->load->view('footer');
            }else{

                $post = $this->input->post();
                $clean = $this->security->xss_clean($post);

                $userInfo = $this->user_model->checkLogin($clean);

                if(!$userInfo){
                    $this->session->set_flashdata('flash_message', 'The login was unsucessful');
                    redirect(site_url().'main/login');
                }
                foreach($userInfo as $key=>$val){
                    $this->session->set_userdata($key, $val);
                }
                redirect(site_url().'main/');
            }

        }


        public function logout()
        {
            $this->session->sess_destroy();
            redirect(site_url().'main/login/');
        }


}

回答1:

This answer may be off because it requires some assumptions.

The Assumptions:

  1. There is only one "role" per user
  2. The value of $userInfo->role is a string
  3. The controller you want to send the authorized user to is main
  4. The methods of the main controller are named the same as the "role" e.g. 'subscriber', 'admin', 'client', 'postman'

If any of the above is false then this answer won't work.

Here's my suggested solution. I'll make comments about it after this code.

public function login()
{
    $this->form_validation->set_rules('email', 'Email', 'required|valid_email');
    $this->form_validation->set_rules('password', 'Password', 'required');

    if($this->form_validation->run())
    {
        $post = $this->input->post();
        //$clean = $this->security->xss_clean($post);

        $userInfo = $this->user_model->checkLogin($post);

        if( ! $userInfo)
        {
            $this->session->set_flashdata('flash_message', 'The login was unsucessful');
            redirect('main/login');
        }

        $this->session->set_userdata($userInfo);
        redirect('main/'.$userInfo->roles);
    }

    $this->load->view('header');
    $this->load->view('login');
    $this->load->view('footer');
}

You're probably wondering why I rearranged everything. Well, mostly because it eliminates the need for an else to go with the if. Less code is good - right?

A call to redirect() ends script execution meaning that any code after a redirect won't run. Because the if($this->form_validation->run()){ code block ends with a call to redirect that's where this function ends. So, you don't need an else. Should validation fail execution go straight to the view loading code.

Your syntax for redirect is wrong. redirect() will build the URL based on your config file values. (docs here) So, make sure $config['base_url'] is set correctly.

Your code

redirect(site_url().'main/');

should be written

redirect('main/');

You probably noticed that I commented out the line

$clean = $this->security->xss_clean($post);

Most developers will argue that XSS prevention should be done on output, not on input. (More than you want to know about XSS prevention HERE.)

Since the input data is being used to select a DB record, it appears the values are escaped, and you're not storing the inputs there is no danger. Using xss_clean() is resource intensive and not useful in this case.

I removed the following loop

foreach ($userInfo as $key => $val)
{
    $this->session->set_userdata($key, $val);
}

and changed it to

$this->session->set_userdata($userInfo);

If you look at the code for set_userdata() and you will find it pretty much uses the exact same code you created. (The code is in /system/core/Session/Session.php around line 785.) Stay DRY and use the framework's toolset. set_userdata() will accept an associative array and do what you need to be done.

Because the value of $userInfo->roles is a string that matches the name of the method you want to redirect them to this call should do the trick.

redirect('main/'.$userInfo->roles);

If main isn't the right controller then change it above. If the method names don't match the role values then additional code will be needed.

Hope this is clear and is helpful.