Hash password after Validator::make - laravel

I want to hash the password after validating the data.
My code:
public function create(Request $request){
$data = Validator::make($request->only(['name', 'email', 'password']), [
'name' => 'required|min:3:max:20',
'email' => 'required|email|unique:users',
'password' => 'required|min:6',
]);
if ($data->fails()) {
//Do something
}else{
User::create($data);
}
}
So how to hash the password after validation?
I tried to override the password inside $data, But it's not working
$data->safe()->only('password') = Hash::make($data->safe()->only('password'));
I can't use $request['password'] as I won't be able to validate it and check if it's empty ..etc.

An alternative approach would be to use an Eloquent Mutator to automatically hash the password field when it is set.
// User Model
public function setPasswordAttribute($value): void
{
$this->attributes['password'] = Hash::make($value);
}
I personally like this approach because you won't have to worry about it in the controllers. You can just set it once and forget about it. :)

The quick answer to your question would be to use the Eloquent make function.
$user = User::make($data);
$user->password = Hash::make($password);
$user->save();
Where $password is where ever you have the password stored. In your case:
$password = $data->safe()->only('password')
There may be a more efficient way, based on your exact intent. In general, the above solution will work.
The make function creates an Eloquent model, but does not store it in the database. That's why you can edit the values and then call $user->save()

Use a mutator method to set the password. Override the method by adding:
public function setPasswordAttribute($value)
{
$this->attributes['password'] = 'some random password generator';
}
there is document:
https://laravel.com/docs/8.x/eloquent-mutators#defining-a-mutator

Related

Laravel Password Basic Hashing

I want to encrypt password in Laravel.But Hash or Crypt are encryting again again every page refresh. So I dont use it.
$pass = Hash::make($user_password);
$pass = Crypt::encrypt($user_password);
How can i do one times encrypt with Hash or Crypt method ? Because I can't do login page with Hash.
I solved this problem
public function login(Request $request)
{
$email = $request->input('user_email');
$password = $request->input('user_password');
$user = BO_USER::where('email', '=', $email)->first();
if (!$user) {
return response()->json(['success'=>false, 'message' => 'Login Fail, please check email id']);
}
if (!Hash::check($password, $user->password)) {
return response()->json(['success'=>false, 'message' => 'Login Fail, pls check password']);
}
//return response()->json(['success'=>true,'message'=>'success', 'data' => $user]);
return redirect('/dashboard');
}
You will use the Hash, cause Crypt can be decrypted.
See documentation:
Hashing for password
Encrypt and decrypt values

Authenticate user without using factory in unit testing

I am new to unit testing. I want to authenticate a user without using Factory. I want my testing code to be simple. I don't know how to use the Factory. Here is my code :
public function loginVerify()
{
$user = factory('App\User')->create();
}
the first thing that you have to do is follow the naming convention
Change
public function loginVerify()
{
$user = factory('App\User')->create();
}
to
public function testLoginVerify()
{
$user = factory('App\User')->create();
}
always use the test as a prefix for your testing function name.
and now as we look at your question, you can simply do this...
public function testLoginVerify()
{
$user_details = [
'email' => 'demo#gmail.com', // the email of a particular user
'password' => 'password' // the password of that user
];
$this->post('/login', $user_details)->assertRedirect('/home');
}
This is the very simplest way to do this.

Disable hashing on Auth::attempt

I am working with an old database without hashed passwords, also this database needs to be unhashed since it is connected to a Runnable JAR.
I did everything to connect it with Laravel 5.3 and it worked, but.. When comes to login it always return false.
Here is the function code:
public function login(Request $request)
{
$this->validate($request, [
'account' => 'required|alpha_num|exists:accounts,account',
'password' => 'required|alpha_num|min:4',
]);
if(Auth::attempt(['account' => $request->account, 'password' => $request->password])){
return redirect()->route('account');
}
return redirect()->back()->withInput();
}
I came to the conclusion that Auth::attempt hashes the given password through the view and when comparing to the unhashed one in the database, returns false.
How can i fix this??
Thank you.
You will need to use another method of manual authentication.
$user = User::where('account', $request->account)
->where('password', $request->password)
->first();
if($user) {
Auth::loginUsingId($user->id);
// -- OR -- //
Auth::login($user);
return redirect()->route('account');
} else {
return redirect()->back()->withInput();
}
You just can add this to your App/User.
If you are using another driver in config/hashing.php - change bcrypt to argon/argon2i
public function getAuthPassword() {
return bcrypt($this->password);
}

Hash::check() return false in laravel 5

I'm just starting with laravel 5, I'm doing a simple login function to check if email and password passed by user matches with the email and password stored in the database. I've been reading the documentation ([https://laravel.com/docs/5.0/hashing1) but Hash::check($content['password'], $user->{'password'}) returns false always. My code looks like this.
When I create a new user I hash the password like that:
$content = json_decode($request->getContent(), true);
$user -> password = Hash::make($content['email']);
And my login function looks like that:
public function login(Request $request)
{
$content = json_decode($request -> getContent(), true);
$user = DB::table('users')->where('email', $content['email'])->first();
if (Hash::check($content['password'], $user->{'password'}))
{
// Redirect to dashboard
}
}
Thanks in advance!!
Actually you are hashing the email instead of password while creating the user. change the code from
$user->password = Hash::make($content['email']);
To
$user->password = Hash::make($content['password']);
i came up with same issue. check database users table, password field. make the size of the field to 60 or more. this fixed mine.
The facade Hash just will encrypt your data:
Hash::make('123456');
is the same that:
$password = bcrypt('123456');
to login a user you need to use AuthController functions:
Auth::attempt(['email' => 'test#test.com' , 'password' => Hash::make('password')]);
it's a example.
If you're receiving a request, you can add this method to login:
if(Auth::attempt(['email' => $request->email, 'password' => $request->password , 'active' => 1])){
flash()->success('Successfully logged in!');
return redirect('/');
}
the attempt function will hash your password field and will compare with database data.

Only update field if form value exists

I'm using Form Model Binding as such and updating my DB using the fill() and save() methods.
{{ Form::model($account) }}
{{ Form::text('name', null, array('class'=>'class')) }}
{{ Form::text('email', null, array('class'=>'class')) }}
{{ Form::password('password', array('class'=>'class')) }}
{{ Form::password('password_confirmation', array('class'=>'class')) }}
{{ Form::close() }}
Which fires my editAccount controller method:
$rules = array(
'name' => array('required'),
'email' => array('required'),
'password' => array('confirmed')
);
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails())
{
// Redirect
}
// Save to DB
$account->fill(Input::all());
$account->save();
Which works fine, but if no password was supplied (because the user doesn't want to update/modify it) then the password field is set to null in the db. So, I only want the password field to update if a new password value is supplied via the form.
I know I can do the following:
// Set the fields manually
$account->name = Input::get('name');
$account->email = Input::get('email');
// Only update the password field if a value is supplied
if (Input::get('password')) {
$account->password = Input::get('password');
}
$account->save();
However I'm wondering if there is a more cleaner way to handle this? Like an UpdateOnlyIfValueExists() method within Laravel/Eloquent.
Using Input::only('foo', 'bar') will grab only the values needed to complete the request - instead of using Input::all().
However, if 'foo' or 'bar' doesn't exist within the input, the key will exist with the value of null:
$input = Input::only('foo', 'bar');
var_dump($input);
// Outputs
array (size=2)
'foo' => null
'bar' => null
To filter in a clean way, any values with a null value:
$input = array_filter($input, 'strlen');
In your example, this would replace: $account->fill(Input::all());
Create Base model and override update function like
/**
* #param array $attributes
* #return mixed
*/
public function update(Array $attributes = array()){
foreach($attributes as $key => $value){
if(!is_null($value)) $this->{$key} = $value;
}
return $this->save();
}
After use:
$model = Model::find($id);
$model->update(Input::only('param1', 'param2', 'param3'));
Check this, you can validate if password is present in input, and exclude it from mass assignment. You can use Input::except and Input::only for this purpose
public function update ($id) {
$user = User::findOrFail ($id);
if (Input::get ('password') == '') {
$user->update (Input::except ('password'));
}
else {
$user->update (Input::all ());
}
//return something
}
$data = $request->password ? $request->all():$request->except('password');
$user->update($data);
This will only update the password if it's not null
I would stick with your latter example. Another option would be to use a mutator which checks the value there, and doesn't update if the value is empty. But in my opinion, Eloquent should not be responsible for doing that.
I'd also avoid using ALL input with fill(). Choose only what you want.
This is a pretty shitty and common issue with Laravel (and other frameworks). My solution resembles some of the previous...
I always have the form data Input::all() stored in a variable at the beginning of the update/store methods. Since you usually need it at least twice (validate and create/update) it seems like a good practice. Then with that and before doing anything else I check in update() for the presence of the password, something like this:
$aFormData = Input::all();
if ( !$aFormData['password'] )
unset( $aFormData['password'] );
... the rest of your code here using $aFormData ;) ...
And that's it, hope it helps!
A much cleaner approach would be to use Eloquent Mutators
Under no circumstances would you allow a null or an empty string as password so you can safely define the following mutator in your Account model.
// Only accept a valid password and
// hash a password before saving
public function setPasswordAttribute($password)
{
if ( $password !== null & $password === '' )
{
$this->attributes['password'] = bcrypt($password);
}
}
The above mutator will only set a password attribute if it is not null and an empty string. It also hashes the password before saving so you do not need to do it in your controller action or application elsewhere.
Best approche is to use mutators as Noman Ur Rehman said above, but he had mistake in his code. Right one will be:
public function setPasswordAttribute($password){
if ( $password !== null && $password !== '' )
$this->attributes['password'] = Hash::make($password);
}

Resources