I want to apply soft delete in laravel5.4 inbuilt reset password. Due to duplicate email of soft delete deleted email password is change but not the correct one. I am getting stuck to where apply deleted should be null instead of email checking only. that's why it fetches the deleted record insted of correct one. My reset password controller is given below. Please check my reset controller & suggest any solution please.
class ResetPasswordController extends Controller
{
use ResetsPasswords;
protected $redirectTo = 'member/welcome';
public function showResetForm(Request $request, $token = null)
{
return view('frontend.member.auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
public function reset(Request $request)
{
$this->validate($request, $this->rules(), $this->validationErrorMessages());
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed|min:8|regex:/^.*(?=.{3,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[#!$#%^*()-_]).*$/',
];
}
/**
* Get the password reset validation error messages.
*
* #return array
*/
protected function validationErrorMessages()
{
return [
'password.regex' => 'The password must contain at least one uppercase, one lowercase, one number and one special(#!$#%...) character.'
];
}
protected function resetPassword($user, $password)
{
$password = app('hash')->needsRehash($password) ? Hash::make($password) : $password;
$user->forceFill([
'password' => $password,
'remember_token' => Str::random(60),
])->save();
$this->guard()->login($user);
}
public function broker()
{
return Password::broker('members');
}
protected function guard()
{
return Auth::guard('web_member');
}
}
Please help thanks in advance.I am new to laravel please help.
Just need to pass the correct user to resetPassword() function like
public function reset(Request $request)
{
$this->validate($request, $this->rules(), $this->validationErrorMessages());
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$user = User::where('email', $user->email)->whereNull('deleted_at')->first();
$this->resetPassword($user, $password);
}
);
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
Related
This is how I would make such a function
Controller code
public function store(RegistrationStoreRequest $request){
$user = User::create($request->validated());
Auth::login($user);
return redirect()->home();
}
This is my Request form code
public function rules()
{
return [
'name' => 'required',
'email' => 'required|email',
'password' => 'required|confirmed'
];
}
You have two options:
Create a value mutator:
public function setPasswordAttribute($value) {
$this->attributes['password'] = Hash::make($value);
}
however you need to ensure you never prehash the password.
Hash in controller
public function store(RegistrationStoreRequest $request){
$user = User::create(array_merge(Arr::except($request->validated(), 'password'), [ 'password' => Hash::make($request->password) ]));
Auth::login($user);
return redirect()->home();
}
The easiest and most clean way is to use a custom cast for password field, first create UserPasswordCast.php class:
<?php
//app/Casts/UserPasswordCast.php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Support\Facades\Hash;
class UserPasswordCast implements CastsAttributes
{
public function get($model, $key, $value, $attributes)
{
return $value;
}
public function set($model, $key, $value, $attributes)
{
//return hashed value
return Hash::make($value);
}
}
Suggested location:
app/Casts/UserPasswordCast.php
Then update your 'user' model to use this cast, add "$casts" array or update it if existed:
use App\Casts\UserPasswordCast;
...
protected $casts = [
...
'password' => UserPasswordCast::class
];
That's it, you don't have to worry about password again
Just save your user model as it:
public function store(RegistrationStoreRequest $request)
{
$user = User::create($request->validated());
Auth::login($user);
return redirect()->home();
}
For more info please check:
https://laravel.com/docs/8.x/eloquent-mutators#custom-casts
=>create method function add in User.php(Model).
public static function create($user, $request)
{
if (isset($request->name)) {
$user->name = $request->name;
}
if (isset($request->email)) {
$user->email = $request->email;
}
if (isset($request->password)) {
$user->password = bcrypt($request->password);
}
if (isset($request->confirmpassword)) {
$user->confirmpassword = $request->confirmpassword;
}
$user->save();
return $user;
}
=>New user create with validate your all request field.
public function store(RegistrationStoreRequest $request){
$user = User::create(New User,$request);
Auth::login($user);
return redirect()->home();
}
Please try this code it is working.
I need to allow login only for allowed users, this is my controller:
class LoginController extends Controller
{
public function index()
{
return view('login');
}
public function login(Request $request)
{
$credentials = $request->only('user', 'password');
if (!Auth::attempt($credentials)) {
return back()->with('error', 'Usuario o ContraseƱa Invalidos!');
} else if (Auth::user()->status != 1) {
return back()->with('error', 'Usuario no autorizado');
}
$request->session()->regenerate();
return redirect('home');
}
public function logout(Request $request)
{
Auth::logout();
$request->session()->regenerate();
return redirect('/login');
}
}
it works but it is allowing all the users, even those with status = 0, what am i doing wrong?
thanks for your help...
Auth::attempt accept extra query conditions to the authentication query in addition to the user's email and password.
if (Auth::attempt(['email' => $email, 'password' => $password, 'status' => 1])) {
// Authentication was successful...
}
In your LoginControllere add this:
protected function credentials(\Illuminate\Http\Request $request)
{
//return $request->only($this->username(), 'password');
return [$this->username() => $request->{$this->username()}, 'password' => $request->password, 'status' => 1];
}
I have a multi Tenant / multi DB application & each Tenant has it's own Subdomain with Laravel 7.2
When I go to rootdomain.com/super-admin I can login.
When I go to demo.rootdomain.com/login I can login (default database).
When I go to tenant1.rootdomain.com/login I can NOT login.
I'm using Laravels Auth scaffolding.
I have narrowed it down to the ValidatesRequests trait. If I add the email/password manually I can login to tenant1.rootdomain.com/login
So it looks like this:
public function validate(Request $request, array $rules,
array $messages = [], array $customAttributes = [])
{
return [
"email" => "tenant1#rootdomain.com",
"password" => "#Abc123"
];
return $this->getValidationFactory()->make(
$request->all(), $rules, $messages, $customAttributes
)->validate();
}
Here is my TenantProvider to switch connection for each DB
public function register()
{
if($this->app->runningInConsole()){
return;
}
$host = request()->getHttpHost();
$new_host = explode('.', str_replace('www.', '', $host));
//host must contain at least 3
if(count($new_host) == 3 && $new_host[0] != 'dev'){
config(['database.connections.mysql.database' => 'c4_'.$new_host[0].'_app']);
DB::purge('mysql');
DB::reconnect('mysql');
try {
DB::connection()->getPdo();
if(!DB::connection()->getDatabaseName()){
//reset to default
config(['database.connections.mysql.database' => 'c4_app']);
DB::purge('mysql');
DB::reconnect('mysql');
die("Could not find the database OR Subdomain. Please check your configuration.");
}
} catch (\Exception $e) {
//reset to default
config(['database.connections.mysql.database' => 'c4_app']);
DB::purge('mysql');
DB::reconnect('mysql');
die("Could not open connection to database server. Please check your configuration OR subdomain.");
}
}
// dump('DB Connected...ready to go c4_mvp_app ',DB::connection()->getDatabaseName());
}//end function
And my LoginController
namespace App\Http\Controllers\Auth;
use App\Models\GlobalSetting;
use App\Http\Controllers\Front\FrontBaseController;
use App\Models\Social;
use App\Traits\SocialAuthSettings;
use App\Models\User;
use Carbon\Carbon;
use Froiden\Envato\Traits\AppBoot;
use GuzzleHttp\Client;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Laravel\Socialite\Facades\Socialite;
class LoginController extends FrontBaseController
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers, AppBoot, SocialAuthSettings;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/admin/dashboard';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
// dd('Base Login', $this->redirectTo);
parent::__construct();
$this->middleware('guest', ['except' => 'logout']);
}
public function showLoginForm()
{
if (!$this->isLegal()) {
// return redirect('verify-purchase');
}
if ($this->setting->front_design == 1 && $this->setting->login_ui == 1) {
return view('saas.login', $this->data);
}
$this->pageTitle = 'Login Page';
return view('auth.login', $this->data);
}
protected function validateLogin(\Illuminate\Http\Request $request)
{
$setting = GlobalSetting::first();
$rules = [
$this->username() => 'required|string',
'password' => 'required|string'
];
// User type from email/username
$user_email = $request->{$this->username()};
$user = User::where('email', $user_email)->first();
if (!is_null($setting->google_recaptcha_key) && (is_null($user) || ($user && !$user->super_admin))) {
$rules['g-recaptcha-response'] = 'required';
}
if (module_enabled('Subdomain')) {
$rules = $this->rulesValidate($user);
}
$this->validate($request, $rules);
}
public function googleRecaptchaMessage()
{
throw ValidationException::withMessages([
'g-recaptcha-response' => [trans('auth.recaptchaFailed')],
]);
}
public function companyInactiveMessage()
{
throw ValidationException::withMessages([
$this->username() => [trans('auth.companyStatusInactive')],
]);
}
public function validateGoogleRecaptcha($googleRecaptchaResponse)
{
$setting = GlobalSetting::first();
$client = new Client();
$response = $client->post(
'https://www.google.com/recaptcha/api/siteverify',
[
'form_params' =>
[
'secret' => $setting->google_recaptcha_secret,
'response' => $googleRecaptchaResponse,
'remoteip' => $_SERVER['REMOTE_ADDR']
]
]
);
$body = json_decode((string) $response->getBody());
return $body->success;
}
public function login(\Illuminate\Http\Request $request)
{
$setting = GlobalSetting::first();
$this->validateLogin($request);
// User type from email/username
$user = User::where($this->username(), $request->{$this->username()})->first();
// dd('LoginController login 140', $user);
if ($user && !$user->super_admin && $user->company->status == 'inactive' && !$user->hasRole('client')) {
return $this->companyInactiveMessage();
}
// Check google recaptcha if setting is enabled
if (!is_null($setting->google_recaptcha_key) && (is_null($user) || ($user && !$user->super_admin))) {
// Checking is google recaptcha is valid
$gRecaptchaResponseInput = 'g-recaptcha-response';
$gRecaptchaResponse = $request->{$gRecaptchaResponseInput};
$validateRecaptcha = $this->validateGoogleRecaptcha($gRecaptchaResponse);
if (!$validateRecaptcha) {
return $this->googleRecaptchaMessage();
}
}
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (
method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)
) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
protected function credentials(\Illuminate\Http\Request $request)
{
//return $request->only($this->username(), 'password');
// dd('credentials 185',$request->{$this->username()});
return [
'email' => $request->{$this->username()},
'password' => $request->password,
'status' => 'active',
'login' => 'enable'
];
}
protected function redirectTo()
{
$user = auth()->user();
if ($user->super_admin == '1') {
return 'super-admin/dashboard';
} elseif ($user->hasRole('admin')) {
$user->company()->update([
'last_login' => Carbon::now()->format('Y-m-d H:i:s')
]);
return 'admin/dashboard';
}
if ($user->hasRole('employee')) {
return 'member/dashboard';
}
if ($user->hasRole('client')) {
return 'client/dashboard';
}
}
/**
* Log the user out of the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$user = auth()->user();
$this->guard()->logout();
$request->session()->invalidate();
if (module_enabled('Subdomain')) {
if ($user->super_admin == 1) {
return $this->loggedOut($request) ?: redirect(route('front.super-admin-login'));
}
}
return $this->loggedOut($request) ?: redirect('/login');
}
private function rulesValidate($user)
{
if (Str::contains(url()->previous(), 'super-admin-login')) {
$rules = [
$this->username() => [
'required',
'string',
Rule::exists('users', 'email')->where(function ($query) {
$query->where('super_admin', '1');
})
],
'password' => 'required|string',
];
} else {
$company = getCompanyBySubDomain();
$client = false;
$companies = [];
if ($user && User::isClient($user->id)) {
$client = true;
foreach ($user->client as $item) {
$companies[] = $item->company_id;
}
}
$rules = [
$this->username() => [
'required',
'string',
Rule::exists('users', 'email')->where(function ($query) use ($company, $companies, $client) {
if ($client) {
$query->whereIn('company_id', $companies);
} else {
$query->where('company_id', $company->id);
}
})
],
'password' => 'required|string',
];
}
// dd('rulesValidate 281',$rules);
return $rules;
}
public function redirect($provider)
{
$this->setSocailAuthConfigs();
return Socialite::driver($provider)->redirect();
}
public function callback(Request $request, $provider)
{
$this->setSocailAuthConfigs();
$redirectRoute = module_enabled('Subdomain') ? 'front.workspace' : 'login';
try {
if ($provider != 'twitter') {
$data = Socialite::driver($provider)->stateless()->user();
} else {
$data = Socialite::driver($provider)->user();
}
} catch (\Exception $e) {
if ($request->has('error_description') || $request->has('denied')) {
return redirect()->route($redirectRoute)->withErrors([$this->username() => 'The user cancelled ' . $provider . ' login']);
}
throw ValidationException::withMessages([
$this->username() => [$e->getMessage()],
])->status(Response::HTTP_TOO_MANY_REQUESTS);
}
$user = User::where('email', '=', $data->email)->first();
if ($user) {
// User found
\DB::beginTransaction();
Social::updateOrCreate(['user_id' => $user->id], [
'social_id' => $data->id,
'social_service' => $provider,
]);
if ($user->super_admin == 1) {
\Auth::login($user);
return redirect()->intended($this->redirectPath());
}
\DB::commit();
$user->social_token = Str::random(60);
$user->save();
if (module_enabled('Subdomain')) {
return redirect()->to(str_replace(request()->getHost(), $user->company->sub_domain, route('login')) . '?token=' . $user->social_token);
}
\Auth::login($user);
return redirect()->intended($this->redirectPath());
}
if (module_enabled('Subdomain')) {
return redirect()->route($redirectRoute)->withErrors(['sub_domain' => Lang::get('auth.sociaLoginFail')]);
}
throw ValidationException::withMessages([
$this->username() => [Lang::get('auth.sociaLoginFail')],
])->status(Response::HTTP_TOO_MANY_REQUESTS);
}
}
Let me know if you need any other code...thank you!
The code works fine....turns out it was a caching issue.
In my first controller, I guess, I use the most basic way of creating a user password
EmployeeController
public function store(Request $request){
$user = User::create(array(
'username' => $request->username,
'password' => Hash::make($tempPassword = Str::random(8)))
);
$employee->user()->associate($user);
$employee->save();
}
Shen it comes to checking the password with Hash::check() in the second controller it always fails
ResetPasswordController
public function index(ResetPasswordRequest $request){
$request->validated();
$emp = Student::find($request->id);
if ($emp->user->checkCredentials($request->password)) { //always false
}
}
However, if update password in the same controller (just for testing) it works just fine
ResetPasswordController
public function index(ResetPasswordRequest $request){
$request->validated();
$emp = Student::find($request->id);
$emp->user->update(['password' => Hash::make('abc')]);
if ($emp->user->checkCredentials('abc')) { //...true
}
}
User
public function checkCredentials($password){
return (Hash::check($password, $this->password)) ? true : false;
}
I don't change the app key between creating and checking the user passwords. Any ideas where else should I look?
I have two separated Auths for the project one for Doctors (Login, Register & Reset)[Accounts Table] and the other for Patients (clients) (Login, Register & Reset) [Patients table].
Each Patient can be registered with the same mail with any doctor (Account).
i have done all the stuff but my problem is when the patient resets his password inside specific doctor account. Laravel changes the password of the patient mail in patients table ..
My question is: how to add condition to resetPassword method
Ex: where mail = $mail and account_id = $account_id
i successed to override the sendRequestResetLinkMail method by
PatientAuth\ForgotPasswordController.php:
public function sendResetLinkEmail(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
]);
$response = $this->broker()->sendResetLink([
'email' => $request->input('email'),
'account_id' => Hashids::decode($request->segment(3)),
]);
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
ResetPasswordController.php:
class ResetPasswordController extends Controller
{
public function __construct()
{
$this->middleware('lang');
}
//Client redirect path
protected function redirectTo(Request $request)
{
return route('WSG.view.home', $request->segments(3));
}
//trait for handling reset Password for patient / client
use ResetsPasswords;
//Show form to patient / client where they can reset password
public function showResetForm(Request $request, $id, $token = null)
{
$id = Hashids::decode($id);
$main_settings = WSGeneratorMainSetting::where('account_id', $id)->first();
return view('doctor_website.layouts.reset',
[
'token' => $token,
'email' => $request->email,
'main_settings' => $main_settings,
]
);
}
protected function credentials(Request $request)
{
return $request->only(
'email', 'password', 'password_confirmation', 'account_id' , 'token'
);
}
//returns Password broker of seller
public function broker()
{
return Password::broker('clients');
}
//returns authentication guard of seller
protected function guard()
{
return Auth::guard('client');
}
}