Laravel Auth attempt failing - php

I really try to debug my issues on my own before I bring them here, but I seriously cannot find a solution to my laravel auth problem, though it seems to be a common issue.
My authentication will not login. It always returns false and I don't understand why.
I've read through some other questions here, and their solutions haven't solved my particular situation.
My User model implements UserInterface and Remindable Interface.
My password is hashed upon creating it to the database.
My password field in my database is varchar 100, which should be more than enough to hash the password.
The user I'm logging is has been created and activated in the database.
Thank you so much for any insight.
User Model
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $fillable = array('email', 'username', 'password', 'password_temp', 'code', 'active');
public $timestamps = false;
protected $softDelete = false;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'Users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = 'password';
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
}
Account Controller
class AccountController extends BaseController {
public function getLogin() {
return View::make('account.login');
}
public function postLogin() {
$validator = Validator::make(Input::all(),
array(
'email' => 'required',
'password' => 'required'
)
);
if($validator->fails()) {
return Redirect::route('login')
->withErrors($validator);
} else {
$auth = Auth::attempt(array(
'email' => Input::get('email'),
'password' => Input::get('password'),
'active' => 1
));
if($auth) {
return Redirect::route('Create-Account');
}
}
return Redirect::route('login')
->with('global', 'There was a problem logging you in. Please check your credentials and try again.');
}
public function getCreate() {
return View::make('account.create');
}
public function getviewReturn() {
return View::make('account.return');
}
public function postCreate() {
$validator = Validator::make(Input::all(),
array(
'email' => 'required|max:50|email|unique:Users',
'username' => 'required|max:15|min:4|unique:Users',
'password' => 'required|min:6',
'password2' => 'required|same:password'
)
);
if ($validator->fails()) {
return Redirect::route('Post-Create-Account')
->withErrors($validator)
->withInput();
}
else {
$email = Input::get('email');
$username = Input::get('username');
$password = Input::get('email');
$code = str_random(60);
$user = User::create(array(
'email' => $email,
'username' => $username,
'password' => Hash::make($password),
'code' => $code,
'active' => 0));
});
return Redirect::to('account/return')
Routes
Route::group(array('before' => 'guest'), function() {
Route::group(array('before' => 'csrf'), function() {
Route::post('/account/create', array(
'as' => 'Post-Create-Account',
'uses' => 'AccountController#postCreate'
));
Route::post('/account/login', array(
'as' => 'postlogin',
'uses' => 'AccountController#postLogin'
));
});
Route::get('/account/login', array(
'as' => 'login',
'uses' => 'AccountController#getLogin'
));
Route::get('/account/create', array(
'as' => 'Create-Account',
'uses' => 'AccountController#getCreate'
));
Route::get('/account/activate/{code}', array(
'as' => 'Activate-Account',
'uses' => 'AccountController#getActivate'

When creating the user you've done
$password = Input::get('email');
It should be
$password = Input::get('password');
so if you try and login with the "email" as the password - it will work! :)
So if you change this
else {
$email = Input::get('email');
$username = Input::get('username');
$password = Input::get('email');
$code = str_random(60);
$user = User::create(array(
'email' => $email,
'username' => $username,
'password' => Hash::make($password),
'code' => $code,
'active' => 0));
});
to this
else {
$user = User::create(array(
'email' => Input::get('email'),
'username' => Input::get('username'),
'password' => Hash::make(Input::get('password');),
'code' => str_random(60),
'active' => 0));
});
that cleans up your code and fixes the issue.

Your code looks right to me, so you have to check some things:
1) A manual attempt works for you?
dd( Auth::attempt(['email' => 'youremail', 'password' => 'passw0rt']) );
2) The user hash checks manually?
$user = User::find(1);
var_dump( Hash::check($user->password, 'passw0rt') );
dd( Hash::check($user->password, Input::get('password')) );

Try to add primaryKey field in your user model. It should be something like that:
protected $primaryKey = 'user_id';

I think Apache version problem. You need to update Apache2.4.

Related

assertRedirect causing output of email already exists - PHP Testing

So my test case in laravel is the following:
public function test_user_can_sign_up_using_the_sign_up_form()
{
$user = User::factory()->create();
$user = [
'username' => $user->username,
'email' => $user->email,
'password' => $user->password,
'password_confirmation' => $user->password,
'dob' => $user->dob
];
$response = $this->post('/register', $user);
// Removes password confirmation from array
array_splice($user, 3);
$this->assertDatabaseHas('users', $user);
$response->assertRedirect('/home');
}
This line:
$response->assertRedirect('/home');
is causing the test to fail and get an output of 'The email has already been taken' Why is this the case? I want to check upon sign up, the user is directed to the home page which it does but my test fails.
The user is being created in the database so that part works fine.
UserFactory:
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'username' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'dob' => fake()->date(),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return static
*/
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
Okay I will explain your test case to you.
You are testing a register feature of your app.
$user = User::factory()->create();
$user = [
'username' => $user->username,
'email' => $user->email,
'password' => $user->password,
'password_confirmation' => $user->password,
'dob' => $user->dob
];
$response = $this->post('/register', $user);
this block of code is wrong because you are using the data of a User already inside the database to create an account. So it will naturally fails since the data is already inside the database the moment you call the User::factory()->create().
So instead of that you should pass a data that looks like you are the one registering.Remove the User::factory()->create() then replace the array $user with hard coded data or use the fake() helper.
$user = [
'username' => fake()->userName(),
'email' => fake()->unique()->safeEmail(),
'password' => 'password',
'password_confirmation' => 'password',
'dob' => 'asldkjasd'
];
$response = $this->post('/register', $user);
$response->assertValid();
$this->assertDatabaseHas('users', [
'email' => $user['email'],
]);
$response->assertRedirect('/home');

404 error when submitting user form in the registrationController laravel

I get a 404 error when I try to insert user's details into multiple tables during registration
my user model:
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
use Notifiable;
use HasRoles;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username','accno', 'email', 'password', 'role', 'status', 'activation_code'
];
protected $guarded = [];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
// a mutator for the email attribute of our model with email validation check and check to avoid duplicate email entries.
protected $table = 'users';
public $timestamps = false;
public $incrementing = false;
public function setEmailAttribute($email)
{
// Ensure valid email
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \Exception("Invalid email address.");
}
// Ensure email does not exist
elseif (static::whereEmail($email)->count() > 0) {
throw new \Exception("Email already exists.");
}
$this->attributes['email'] = $email;
}
public function setPasswordAttribute($password)
{
$this->attributes['password'] = Hash::make($password);
}
public function profiles()
{
return $this->hasOne(profiles::class);
}
public function accounts()
{
return $this->hasOne(accounts::class);
}
public function transactions()
{
return $this->hasMany(transactions::class);
}
}
I try refactoring by separating my validation code from my logic using RegisterUserTrait
<?php
namespace App\Traits;
use App\User;
use App\Profile;
use App\Account;
use Keygen;
trait RegisterUser
{
public function registerUser($fields)
{
$user = User::create([
'username' => $fields->username,
'accno' => $this->generateAccountNumber(),
'email' => $fields->email,
'password' => $fields->password = bcrypt(request('password')),
'roles' => $fields->roles,
'activation_code' => $this->generateToken()
]);
Profile::create([
'accno' => $user->accno,
'username' => $user->username,
'acc_type' => $fields->acc_type,
'firstname' => $fields->firstname,
'lastname' => $fields->lastname,
'nationality' => $fields->nationality,
'occupation' => $fields->occupation,
'address' => $fields->address,
'city' => $fields->city,
'state' => $fields->state,
'zipcode' => $fields->zipcode,
'phoneno' => $fields->phoneno,
'dob' => $fields->dob,
'gender' => $fields->gender,
'martial_status' => $fields->martial_status,
'user_image' => $fields->user_image,
]);
Account::create([
'accno' => $user->accno,
'username' => $user->username,
]);
return $user;
}
then storing the data using my registrationController:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\RegistrationRequest;
use App\Traits\RegisterUser;
class RegistrationController extends Controller
{
use RegisterUser;
public function show()
{
return view('auth/register');
}
public function register(RegistrationRequest $requestFields)
{
//calling the registerUser method inside RegisterUser trait.
$user = $this->registerUser($requestFields);
return redirect('/login');
}
}
but when I register the user, the data is only saved in the create_user_table and return a 404 page not found error. How can I save the data to the selected table and redirect to the login page?
As fa as i can see this is not true for foreign key relations in User Model
public function profiles()
{
return $this->hasOne(profiles::class);
}
public function accounts()
{
return $this->hasOne(accounts::class);
}
public function transactions()
{
return $this->hasMany(transactions::class);
}
it should be as follows;
public function profiles()
{
return $this->hasOne(Profile::class);
}
public function accounts()
{
return $this->hasOne(Account::class);
}
public function transactions()
{
return $this->hasMany(Transaction::class);
}
Try this
public function registerUser($fields)
{
$user = User::create([
'username' => $fields->username,
'accno' => $this->generateAccountNumber(),
'email' => $fields->email,
'password' => $fields->password = bcrypt(request('password')),
'roles' => $fields->roles,
'activation_code' => $this->generateToken()
]);
$user->userprofile =Profile::create([
'accno' => $user->accno,
'username' => $user->username,
'acc_type' => $fields->acc_type,
'firstname' => $fields->firstname,
'lastname' => $fields->lastname,
'nationality' => $fields->nationality,
'occupation' => $fields->occupation,
'address' => $fields->address,
'city' => $fields->city,
'state' => $fields->state,
'zipcode' => $fields->zipcode,
'phoneno' => $fields->phoneno,
'dob' => $fields->dob,
'gender' => $fields->gender,
'martial_status' => $fields->martial_status,
'user_image' => $fields->user_image,
]);
$user->useraccount = Account::create([
'accno' => $user->accno,
'username' => $user->username,
]);
return $user;
}
If you are using a voyager package then there is a log file where you will find error messages that can help you understand the exact problem .
the log interface existe in voyager admin panel in :
Tools => Compass => Logs
look at this image :
Try this in your User model
protected static function boot()
{
protected static function boot()
parent::boot();
static::created(function ($user){
$user->profiles()->create([
'accno' => $user->accno,
'username' => $user->username,
.... => ....
]);
$user->accounts()->create([
'accno' => $user->accno,
'username' => $user->username,
]);
});
}
An error 404 is often a problem with a route.
As requested by Christos Lytras in a comment, we need to see your routes/web.php and the output of php artisan route:list to verify.
I believe the redirect in your registrationController is not pointing to a valid url:
return redirect('/login');
Without seeing your routes I can't say for sure but if your login route name is defined, you can do:
return redirect()->route('login');
Please share your routes file to confirm.
create() method is used for mass assignment. you will need to specify either a fillable or guarded attribute on the model. So check the fillable attribute on Profile and Account Model.

How to mock user creation if password is hidden in Laravel 5.5 unit tests

I have a unit acceptance test where I am mocking the creation of a user.
class UserAcceptanceApiTest extends TestCase
{
use WithoutMiddleware;
public function setUp()
{
parent::setUp();
$this->User = factory(App\Models\User::class)->make([
'id' => '999',
'name' => 'Name',
'email' => 'test#example.com',
'password' => bcrypt('password'),
]);
$this->User = factory(App\Models\User::class)->make([
'id' => '999',
'name' => 'Name',
'email' => 'test#example.com',
'password' => bcrypt('password'),
]);
$user = factory(App\Models\User::class)->make();
$this->actor = $this->actingAs($user);
}
public function testStore()
{
$response = $this->actor->call('POST', 'api/users', $this->User->toArray());
$this->assertEquals(200, $response->getStatusCode());
$this->seeJson(['id' => 999]);
}
}
I get the following exception "Field 'password' doesn't have a default value.
This is because in my User model I have the following:
protected $hidden = ['password', 'remember_token'];
So it automatically removes the password field from the JSON.
Is there a way I can override this only for this test? As I want to keep the password as a hidden attribute.
public function testStore()
{
$this->User->makeVisible(['password']);
$response = $this->actor->call('POST', 'api/users', $this->User->toArray());
$this->assertEquals(200, $response->getStatusCode());
$this->seeJson(['id' => 999]);
}

Admin login laravel 4

I edited the store method , now the problem is that when i try to login it redirect to www.example.com/admin but it shows a NotFoundHttpException.
The routes.php file
Route::get('/admin', 'SessionsController#create');
Route::get('/logout', 'SessionsController#destroy');
Route::get('profile', function()
{
return "welcome! Your username is" . Auth::admin()->username;
});
Route::resource('sessions', 'SessionsController', ['only' => ['index', 'create', 'destroy', 'store']]);
here is the controller SessionsController.php
<?php
class SessionsController extends \BaseController {
/**
* Show the form for creating a new resource.
*
* #return Response
*/
public function create()
{
return View::make('admins');
}
/**
* Store a newly created resource in storage.
*
* #return Response
*/
public function store()
{
$rules = array('username' => 'required', 'password' => 'required');
$validator = Validator::make(Input::all(), $rules);
if($validator -> passes()){
$credentials = array(
'username' => Input::get('username'),
'password' => Input::get('password')
);
if(Auth::admin($credentials,true)){
$username = Input::get('username');
return Redirect::to("admin/{$username}");
} else {
return Redirect::to('/admin')->withErrors('Username or password invalid');
}
} else {
return Redirect::to('/admin')->withErrors($validator->messages());
}
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return Response
*/
public function destroy($id)
{
Auth::logout();
return Redirect::home();
}
}
the admins.blade.php
{{Form::open(array('route' => 'sessions.store'))}}
<h1>ADMIN LOGIN </h1>
{{Form::label('username', 'Username')}}
{{Form::text('username')}}
{{Form::label('password', 'Password')}}
{{Form::password('password')}}
{{Form::submit('Login')}}
{{$errors->first()}}
{{Form::close()}}
and here is the model Admin.php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Admin extends Eloquent implements UserInterface, RemindableInterface {
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password', 'remember_token');
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'admins';
}
I also installed ollieread multiauth
and here is auth.php file
return array(
'multi' => array(
'admin' => array(
'driver' => 'database',
'model' => 'Admin',
'table' => 'admins'
),
'user' => array(
'driver' => 'eloquent',
'model' => 'User',
'table' => 'users'
)
),
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
In your admin template you set the goto url as sessions.store which hits SessionsController::store in that method you have a debug function dd() which is throwing that string. It get's called because auth::attempt() returns false as by your own code:
if($attempt) return Redirect::intended('/');
So the behavior is exactly doing what it should. If you are succesfully logged in, you are redirected otherwise it will dump through dd()
What you have to do is filter. You have to add custom error message on app/filter.php
Like the following
Route::filter('auth', function()
{
if (Auth::guest())
{
if (Request::ajax())
{
return Response::make('Unauthorized', 401);
}
else
{
return Redirect::guest('/')->with('message', 'Please login first');
}
}
});
Above code, I redirect to / and gave Please login first message.

How I can make authentication using my own class in laravel?

I'm trying to do a basic authentication which considers email and password. My problem comes when I call the method Auth :: attempt I get the following error.
Model
class Usuario extends Eloquent{
protected $table = 'Usuario';
protected $primaryKey = 'idUsuario';
protected $fillable = array('Nombre',
'Apellido',
'TipoUsuario',
'Contrasena',
'Correo',
'Telefono');
}
Controller
class UsuarioController extends BaseController{
public function doLogin(){
$rules = array('correo' => 'required|email',
'contrasena' => 'required');
$validator = Validator::make(Input::all(), $rules);
if($validator->fails()){
return Redirect::to('usuario')
->withErrors($validator)// manda los errores al login
->withInput(Input::except('contrasena')); //
}else{
$userData = array(
'Correo' => Input::get('correo'),
'Contrasena' => Input::get('contrasena')
);
if(Auth::attempt($userData)){
echo 'bien';
}else{
return Redirect::to('login');
}
}
}
public function showLogin(){
return View::make('login');
}
}
Routte
Route::get('usuario', array('uses' => 'UsuarioController#showLogin'));
Route::post('usuario', array('uses' => 'UsuarioController#doLogin'));
Auth.php
return array(
'driver' => 'database',
'model' => 'User',
'table' => 'Usuario',
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
In the process of checking user credentials Laravel calls validateCredentials method when Auth::attempt gets called and in this function (given below) Laravel checks for the password key in the passed array and in your case you are not passing a password key so the error happens.
public function validateCredentials(UserInterface $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
Change the key in the $userData array:
$userData = array(
'email' => Input::get('correo'), // If correo means email
'password' => Input::get('contrasena') // If contrasena means password
);
Also make changes in your database table's field names which represents users table, I think it's your Usuario table.
I'd check to make sure you're passing the correct info to Auth::attempt() in your controller. I use something more like:
$userData = array('email' => Input::get('email'), 'password' => Input::get('password'));

Categories