Laravel's registration saves password incorrectly - laravel

I'm using Laravel 5.5 and I have modified the registration process recently. This is the registration:
$user = User::create([
'gender' => $data['gender'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'status' => 'inactive',
'password' => Hash::make($data['password'])
]);
which works fine so far. However, when I try to log in with the account I recently had created, it'd always tell me that was the wrong password and I don't understand why. I'm not exactly sure whether it was Hash::make() or bcrypt() originally and since they're different, I suppose there must be something wrong with the login.
If I bcrypt a password using Tinker and insert it into the DB, I'm able to login. I thought of modifying the "login code", however, I wouldn't find anything similiar to the registration looking process which would let me alter the used hash algorithm for login, so what's the approach in this case?
Edit: I placed this code above the $user = User::create([]):
dd($data['password'], bcrypt($data['password']), Hash::make($data['password']));
and this is the output:
"testtesttest123456"
"$2y$10$y9bl5muW5AmmMZMMEWL0Qucy7RSfCSzgWXl29PiX2gPRFd3jnNeEC"
"$2y$10$tez1W8fIwpksgpjsZmQqPuYIN4QTtiddhaCnc5zQ2MgeYATiQd9Ym"
The user model (as per request):
class User extends Authenticatable
{
use Notifiable, HasRoles;
const STATE_ACTIVE = 'active';
const STATE_INACTIVE = 'inactive';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name', 'last_name', 'email', 'password', 'status', 'profile_pic', 'api_token', 'activation_code'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
public function setEmailAttribute($email)
{
$this->attributes['email'] = strtolower($email);
}
}

You are double hashing the password. You have a mutator that is hashing the password. You are also hashing the password before passing it to create.
You have the choice of removing that mutator or not hashing the password before assigning it to the model (as assigning it causes the mutator to run). Either one is fine you just have to know which way you are going.
Most likely there is only going to be 2 places a password is getting hashed anyway, so its really not that big of a concern which way you go.
Registration and perhaps a change password/profile type route are basically the only places you will be hashing the password.

If you haven't done anything to the login/registration hasing in the controllers then this should work
$user = User::create([
'gender' => $data['gender'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'status' => 'inactive',
'password' => bcrypt($data['password'])
]);

Related

How to use the reset password mailable given by auth command

I would like to use the reset password mail but in another controller, for I do not know how to code the link in the button for mailtrap or email. So if there is a way of calling the same reset mail password, It would save me some lines. Or if someone could show me how to code that link in another mail function I am okay
Here is the controller I would like to use
public function create()
{
$roles = Role::all();
$addresses = Address::all();
$user = new User();
return view('admin.create', compact('roles', 'addresses', 'user'));
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'address_id' => 'required',
'name'=> 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'role_id' => 'required',
'description' =>['max:255'],
]);
$quickpass = substr( str_shuffle( str_repeat( 'abcdefghijklmnopqrstuvwxyz0123456789', 10 ) ), 0, 10 );
$newuser = User::create([
'address_id' =>$request->address_id,
'name'=> $request->name,
'email' => $request->email,
'password' => Hash::make($quickpass),
'role_id' => $request->role_id,
'description'=> $request->description,
]);
Mail::to($newuser->email)
->send(new NewUserPassReset());
return view('admin.index')->with('message','The user has been created and a password reset email has been sent to them.');
}
The NewUserPassReset is the mailable I created on my own which has only the message but does not have the link
Right now, I am using mailtrap and above is my admin controller and he is the one who supposed to create user for me
I will kindly appreciate any help
Check out Illuminate\Auth\Notifications\ResetPassword.php.
It has the url that you're looking for:
url(config('app.url').route('password.reset', ['token' => $token, 'email' => $email]))
As you see, you'll need an email and a token to generate the reset password link.
Assuming you know the email, you can obtain the token with the Illuminate\Support\Facades\Password facade:
$token = \Password::createToken($user)
Hope this helps.

Hashing a fillable password

I have no idea how to hash fillable password input. I'm trying to hash it then gets stored to the database. Here's what I've done so far
use App\User;
use Illuminate\Http\Request;
class RegistrationController extends Controller
{
public function store()
{
$this->validate(request(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed'
]);
$pass = bcrypt(request()->password);
$user = User::create(request(['name', 'email', $pass]));
auth()->login($user);
return redirect()->home();
}
}
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password'
];
protected $hidden = [
'password', 'remember_token',
];
}
It gives me a QueryException:
SQLSTATE[HY000]: General error: 1364 Field 'password' doesn't have a default value (SQL: insert into users (name, email, updated_at, created_at) values (the name i inserted, email inserted, date timestamp, date timestamp)
When using: $user = User::create(request(['name', 'email', $pass]));, you are passing an array to the request method and one of the elements ($pass) is not a key of $request.
I believe it should look more like:
$user = User::create([
'name' => request('name'),
'email' => request('email'),
'password' => $pass
]);
EDIT
Also, remember that Laravel provides a Hash facade to help you with encryption:
You can also use the Hash facade to do the same as bcrypt.
Thanks to lagbox for the correction.
$hashedPassword = Illuminate\Support\Facades\Hash:make(request('password'));

Laravel, registration and login on same page. Errors on both forms

I'm working on a website with Laravel and I have the registration and login forms on the same page. The only problem is that if I type the wrong password on the login form the error will show on both forms below the password input.
I've googled this and I have seen some other people with this problem but they are all working on a version below 5.4 and all those solutions are different in version 5.4. Does anyone know what exactly I need to change to make this work?
So far I've changed the names in the forms to 'login_password' and 'register_password', but this only gives me errors.
If you're going to go down the route of changing the input names you'll need to update your LoginController and RegisterController.
Login Controller
You will need to add the following:
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required', 'login_password' => 'required',
]);
}
protected function credentials(Request $request)
{
return [
$this->username() => $request->input($this->username()),
'password' => $request->input('login_password'),
];
}
RegisterController (these methods should already exist in the controller, you'll just need to update password to register_password where applicable)
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'register_password' => 'required|min:6|confirmed',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['register_password']),
]);
}
You will also need to include the Request by putting the following at the top of the file with the other use statements:
use Illuminate\Http\Request;
Hope this helps!

How do I modify my Laravel 5.2 registration to assign new users a role in Laravel 5.3?

I'm new to Laravel, and have been trying to build a user-role authentication system. As 5,3 is very new, there are not many resources that are beginner-friendly. I am using the authentication system created by php artisan make:auth, however I am unsure on how to associate my newly created users with a my roles table.
Initially I had been following this video series on YouTube, but the Authentication controllers differ greatly between 5.2/5.3
I'm hoping that someone can help me figure out what must be done to add in an equivalent what is done in the video to the new controller.
Laravel 5.2 Role Association
public function postSignUp(Request $request)
{
$user = new User();
. . .
$user->save();
$user->roles()->attach(Role::where('name', 'User')->first();
}
From Laravel 5.3 RegisterController.php
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
Thanks for reading.
You can modify the auto-generated Controllers:
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$user->roles()->attach(Role::where('name', 'User')->first());
return $user;
}
To attach a role to a user by inserting a record in the intermediate table that joins the models right after creating an account, use the attach method before returning the new User, like this:
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return User
*/
protected function create(array $data)
{
$user = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
//attach default user role to user
$user->roles()->attach(Role::where('name', 'User')->first());
return $user;
}

Query regarding using Sentinel with Laravel and the $fillable array

I'm using Cartalyst Sentinel for the user authentication within Laravel.
I've created my form to add a new user.
For some strange reason the password does not come through Sentinel::register() unless I put the password field into the $fillable array in the User class model.
This is a potential security issue.
How can I get around this? There must be something I am missing when creating a new user with Sentinel (and the Sentinel documents are very light on useful info).
Just a quick rundown of what I'm doing code wise. I have my array filled with the fields that are required to create a user. This array is passed into Sentinel::register(). It all seems to go through fine, but when I go to look in the database, the password field is blank.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'password' => Input::get('password'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name'));
$user = Sentinel::register($newUser);
Just a side note: unfortunately I cannot switch the authentication system. I need to use Sentinel.
Just another way of doing almost same as Jeff's answer.
This should work based on Sentinel code, tho i have not used Sentinel. Test before deploying.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'password' => Input::get('password'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name')
);
Sentinel::register($newUser, function($user) use ($newUser) {
try {
return $user->password = \Hash::make($newUser['password']);
} catch(RuntimeException $e) {
return false;
}
});
Callback runs after fill method, so it should bypass $fillable restriction and you can remove password from fillable if your design requires that.
If false returned in callback then user will not be created.
You'd need to set the password option manually on a new user if you don't want to make it a fillable property.
$newUser = array(
'_token' => Input::get('_token'),
'email' => Input::get('email'),
'first_name' => Input::get('first_name'),
'middle_name' => Input::get('middle_name'),
'last_name' => Input::get('last_name'));
$user = Sentinel::register($newUser);
$user->password = Input::get('password');
$user->save();
You probably need to be hashing the password before you set it too, right? Something like $user->password = \Hash::make(Input::get('password'));. Unless Sentinel does that automatically.

Resources