1
votes

I am trying to authenticate users in my Laravel application.

I am encountering the following problem:

  • using driver database in auth.php: I can login using auth::attempt(), and auth::check is working, but I can't validate if the logged in user has a certain role.
  • using driver eloquent in auth.php: I can login using auth::attempt(), but auth::check is not working. I can however check the role of the logged in user.

edit (question): How can I fix this so that with only one of the drivers, i can do a complete authentication and role check?

Migration tables:

Schema::create('users', function ($table) {
        $table->increments('id');
        $table->integer('group_id')->unsigned();
        $table->string('name', 64);
        $table->string('email', 64)->unique();
        $table->string('username', 64)->unique();
        $table->string('phone', 13);
        $table->string('address', 64);
        $table->boolean('isresponsible');
        $table->string('password', 64);
        $table->rememberToken()->nullable();
    });
Schema::create('roles', function ($table) {
        $table->increments('id');
        $table->string('name');
    });

Schema::create('users_roles', function ($table) {
            $table->integer('user_id')->unsigned();
            $table->integer('role_id')->unsigned();
        }
    );
Schema::table('users_roles', function($table){
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        $table->foreign('role_id')->references('id')->on('roles');
    });

model class User

<?php
use Illuminate\Auth\UserTrait;`
use Illuminate\Auth\UserInterface;`
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;

class User extends Eloquent implements UserInterface, RemindableInterface {


use UserTrait, RemindableTrait;

/**
 * The database table used by the model.
 *
 * @var string
 */
protected $table = 'users';
public $timestamps = false;

public static $rules = ['name' => 'required', 'group_id' => 'required', 'email' => 'required', 'phone' => 'required'];
protected $fillable = ['name', 'group_id', 'email', 'phone', 'address', 'isresponsible', 'password'];

/**
 * The attributes excluded from the model's JSON form.
 *
 * @var array
 */
protected $hidden = array('password', 'remember_token');

public function group()
{
    return $this->belongsTo('Group');
}

public function userroles(){
    return $this->hasMany('Userrole');
}

public function roles()
{
    return $this->belongsToMany('Role', 'users_roles');
}

public function hasRole($check)
{
    dd($this->roles->toArray());
    return in_array($check, array_fetch($this->roles->toArray(), 'name'));
}

public function setBasicPassword($id){
    $user = User::find($id);
    $user->password = Hash::make('changeme');
    $user->save();
}

public function isValid()
{
    $validation = Validator::make($this->attributes, static::$rules);
    if ($validation->passes()) return true;
    $this->messages = $validation->messages();
    return false;
}


/**
 * Get the e-mail address where password reminders are sent.
 *
 * @return string
 */
public function getReminderEmail()
{
    // TODO: Implement getReminderEmail() method.
}

/**
 * Get the unique identifier for the user.
 *
 * @return mixed
 */
public function getAuthIdentifier()
{
    return $this->email;
}

/**
 * Get the password for the user.
 *
 * @return string
 */
public function getAuthPassword()
{
    return $this->password;
}

/**
 * Get the token value for the "remember me" session.
 *
 * @return string
 */
public function getRememberToken()
{
    return $this->remember_token;
}

public function setRememberToken($value)
{
    $this->remember_token = $value;
}

public function getRememberTokenName()
{
    return 'remember_token';
}
}

model Class Role

class Role extends Eloquent
{

protected $table = 'roles';
public $timestamps = false;

public static $rules = ['role_id' => 'required', 'name' => 'required'];
protected $fillable = ['name'];

/**
 * Get users with a certain role
 */
public function userroles()
{
    return $this->belongsToMany('User', 'users_roles');
}
}

HomeController authentication function

 public function authenticate(){
    $rules = array(
        'email'    => 'required|email',
        'password' => 'required|alphaNum|min:3'
    );
    $validator = Validator::make(Input::all(), $rules);
    if ($validator->fails()) {
        return Redirect::to('login')
            ->withErrors($validator)
            ->withInput(Input::except('password'));
    } else {
        $userdata = array(
            'email' => Input::get('email'),
            'password' => Input::get('password')
        );
        if (Auth::attempt($userdata, true)) {
            return Redirect::action('HomeController@index');

        } else {
            return Redirect::action('HomeController@login')->withInput();
        }
    }
}

USING THE DATABASE DRIVER
- auth:attempt() and auth::check are working

$this->beforeFilter('admin', ['only' => ['index']]); //filter in controller
//filter in filters;php
Route::filter('admin', function()
{
if(!Auth::check()) return Redirect::action('HomeController@index');
if(!Auth::user()->hasRole('admin')) return View::make('errors.401');
});

This fails with 'Call to undefined method Illuminate\Auth\GenericUser::hasRole()'

EDIT The database driver return a GenericUser Object, and I need my own User object. Don't know where I can change this.

Workaround:I'd rather not use this, ugly code and filters (or views) should not need to do this

Route::filter('admin', function()
{
    if(!Auth::check()) return Redirect::action('HomeController@index');
    $user = User::find((Auth::user()->id));
    if(!$user->hasRole('admin')){ return View::make('errors.401');}
});

USING THE ELOQUENT DRIVER

  • auth::attempt() succeeds
  • auth::check() fails
  • no error on the filter
1
Have you tried only Auth::attempt($userdata) without the remember option?lukasgeiter
yes, it gives the same resultJorenV
Does Auth::id() work? (when using Eloquent)lukasgeiter
that returns the username/email addressJorenV
Ahaaaa!! writing an answer now :)lukasgeiter

1 Answers

2
votes

The problem is your implementation of getAuthIdentifier(). This method should actually return the primary key of your table and not the username that's used for logging in.

So yours should look like this:

public function getAuthIdentifier(){
    return $this->id;
}

Or actually, I recommend you clean up your model a bit more since all of the getSomeAuthStuff methods are implemented in the two traits.

Use the default model on github as a base and add all your custom code (roles methods, rules etc)

Background info

The value returned from getAuthIdentifier() will be stored in the session.
When using check() afterwards, retrieveById will be called on the UserProvider. And the EloquentUserProvider does this:

public function retrieveById($identifier)
{
    return $this->createModel()->newQuery()->find($identifier);
}

It uses find() which searches for the model by it's primary key (usually id)