I am using laravel 6. I am trying to implement forgot password for my laravel project for the first time. I have customize the default design for login, forgot password, reset password pages. I have integrated mailtrap for sending email. I have successfully implemented flow like -
click forgot password link
get page on which user enters email and click to send reset link
gets the email of resetting link and data like email, token , created_at stores in password_reset table
on click of reset link page with token and email url gets open in new tab(open the page of reset password having email, new password, confirm password)
Further when I type new password and confirm password and click on Reset Password, nothing happens.
my reset.blade.php
<form id="sign_in" name="sign_in" method="POST" action="{{ route('password.update') }}" data-parsley-validate >
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<h1>Reset Password</h1>
<div class="col-md-12 col-sm-12 form-group has-feedback">
{{-- <label for="login_id"><span style="color:red;">*</span>Login ID</label> --}}
<input id="email" type="email" class="form-control has-feedback-left #error('email') is-invalid #enderror" placeholder="Email" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus/>
<span class="fa fa-envelope form-control-feedback left" aria-hidden="true"></span>
#error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
<div class="col-md-12 col-sm-12 form-group has-feedback">
<input id="password" type="password" class="form-control has-feedback-left #error('password') is-invalid #enderror" placeholder="Password" name="password" required autocomplete="new-password" />
<span class="fa fa-pencil form-control-feedback left" aria-hidden="true"></span>
</div>
<div class="col-md-12 col-sm-12 form-group has-feedback">
<input id="password-confirm" type="password" class="form-control has-feedback-left" placeholder="Confirm Password" name="password_confirmation" required autocomplete="new-password" />
<span class="fa fa-pencil form-control-feedback left" aria-hidden="true"></span>
</div>
<button type="submit" class="btn btn-success">Reset Password</button>
</div>
<div class="clearfix"></div>
</form>
I have default controllers generated for auth like 'ConfirmPasswordController, ForgotPasswordController, ResetPasswordController, VerificationController'
ResetPasswordController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Where to redirect users after resetting their password.
*
* #var string
*/
protected $redirectTo = '/dashboard';
}
I have used default route of auth like Auth::routes();
how the passwords reset in database in users table for email and token generated in password_reset table and how the message gets displayed that 'Password reset successfully? This is not working in my case.userstable not changing with new password and entry not gets removed frompassword_reset` table once the reset done successfully.
where and what changes I have to make to make this work? please guide. thanks in advance.
Password Reset in Laravel
Step 1 — Create a Route and a Controller
Create two routes, a controller, and methods through which the email address that requires a password reset will be submitted via the password reset form. The name of these routes, controllers, and methods is totally up to you.
Route::post('reset_password_without_token', 'AccountsController#validatePasswordRequest');
Route::post('reset_password_with_token', 'AccountsController#resetPassword');
Step 2— Change the action property on the default password reset form
<form method="POST" action="{{ url('/reset_password_without_token') }}">
The default password reset form can be found here:
resources/views/auth/passwords/email.blade.php
Step 3 — Create a token and Send Password Reset Link via email
Then add the validatePasswordRequest method in the AccountsController and use or modify the code below.
//You can add validation login here
$user = DB::table('users')->where('email', '=', $request->email)
->first();
//Check if the user exists
if (count($user) < 1) {
return redirect()->back()->withErrors(['email' => trans('User does not exist')]);
}
//Create Password Reset Token
DB::table('password_resets')->insert([
'email' => $request->email,
'token' => str_random(60),
'created_at' => Carbon::now()
]);
//Get the token just created above
$tokenData = DB::table('password_resets')
->where('email', $request->email)->first();
if ($this->sendResetEmail($request->email, $tokenData->token)) {
return redirect()->back()->with('status', trans('A reset link has been sent to your email address.'));
} else {
return redirect()->back()->withErrors(['error' => trans('A Network Error occurred. Please try again.')]);
}
The sendResetEmail method is a private method that sends an email with the reset link to the user. Here you can use whatever email app you choose to use. Maybe, you have a custom email service for your organization, you can use it here, not relying on the options Laravel has by default.
private function sendResetEmail($email, $token)
{
//Retrieve the user from the database
$user = DB::table('users')->where('email', $email)->select('firstname', 'email')->first();
//Generate, the password reset link. The token generated is embedded in the link
$link = config('base_url') . 'password/reset/' . $token . '?email=' . urlencode($user->email);
try {
//Here send the link with CURL with an external email API
return true;
} catch (\Exception $e) {
return false;
}
}
The link generated and sent to the user when clicked will direct the user to your domain.com/password/reset/token?email=’user#email.com’. You can find the view here: resources/views/auth/passwords/reset.blade.php
Step 4 - Reset the User's password
Add this method to the AccountsController. Go through the comments, they explain each step.
public function resetPassword(Request $request)
{
//Validate input
$validator = Validator::make($request->all(), [
'email' => 'required|email|exists:users,email',
'password' => 'required|confirmed'
'token' => 'required' ]);
//check if payload is valid before moving on
if ($validator->fails()) {
return redirect()->back()->withErrors(['email' => 'Please complete the form']);
}
$password = $request->password;
// Validate the token
$tokenData = DB::table('password_resets')
->where('token', $request->token)->first();
// Redirect the user back to the password reset request form if the token is invalid
if (!$tokenData) return view('auth.passwords.email');
$user = User::where('email', $tokenData->email)->first();
// Redirect the user back if the email is invalid
if (!$user) return redirect()->back()->withErrors(['email' => 'Email not found']);
//Hash and update the new password
$user->password = \Hash::make($password);
$user->update(); //or $user->save();
//login the user immediately they change password successfully
Auth::login($user);
//Delete the token
DB::table('password_resets')->where('email', $user->email)
->delete();
//Send Email Reset Success Email
if ($this->sendSuccessEmail($tokenData->email)) {
return view('index');
} else {
return redirect()->back()->withErrors(['email' => trans('A Network Error occurred. Please try again.')]);
}
}
There you have it. This should be enough to get things working.
I had the same problem, I was able to solve it this way,
first i add a route:
Route::get('password/reset/{token}', [App\Http\Controllers\Auth\ResetPasswordController::class, 'showResetForm'])->name('password.reset');
next i add in reset.blade.php
<input type="hidden" name="token" value="{{$token}}">
that's it, it works for me. Maybe someone will also need it
Related
I want to create simple login system and I made a login system, but it is saying wrong login details. I tried doing dump test is returning null. Please see dd test in comment. Unable to logout also due to this reason
My Login Controller is:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Validator;
class LoginController extends Controller
{
public function index()
{
return view('login');
}
public function store(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|alphaNum|min:3'
]);
$user_data = array(
'email' => $request->get('email'),
'password' => $request->get('password')
);
//$user = Auth::user();
//dd($user); I have done dump test but it is returning null
if(Auth::attempt($user_data))
{
return redirect()->route('welcome');
}
else
{
return back()->with('error','wrong Login Details');
}
}
}
My Login Blade is
#if ($message = Session::get('error'))
<div class="alert alert-danger alert-block">
<button type="button" class="close" data-dismiss="alert">×</button>
<strong>{{ $message }}</strong>
</div>
#endif
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<form action="{{route('login.save')}}" style="border:1px solid #ccc" method="post">
{{ csrf_field() }}
<div class="container">
<h1>Login</h1>
<p>Please fill in this form to Login</p>
<hr>
<label for="email"><b>Email</b></label>
<input type="text" placeholder="Enter Email" name="email" value="{{old('name')}}" >
#error('email')
{{$message}}
#enderror
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" >
#error('password')
{{$message}}
#enderror
<label for="psw-repeat"><b>Repeat Password</b></label>
<input type="password" placeholder="Repeat Password" name="psw-repeat" >
<div class="clearfix">
<button type="submit" class="signupbtn">Log in</button>
</div>
</div>
</form>
</body>
</html>
Web route is
Route::get('/register','App\Http\Controllers\RegisterController#index')->name('register');
Route::post('/register/save','App\Http\Controllers\RegisterController#store')->name('register.save');
Route::get('/login','App\Http\Controllers\LoginController#index')->name('login');
Route::post('/login/save','App\Http\Controllers\LoginController#store')->name('login.save');
Route::get('/welcome','App\Http\Controllers\LogoutController#store')->name('logout');
try to debug your code
1- after register look at database. is your password encrypted ?
2- when submit form dd($request->all())
if every thing work fine
3- Auth::attempt($request->only('email', 'password'))
I hope this answer help you to debug your code.
Try running a dd on the controller itself. Use
dd($request->all());
before
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|alphaNum|min:3'
]);
As of right now, there is no indication that your input data is even reaching the controller. Your route may not even be correct, it is impossible to say without knowing your project structure or the names of the file. If the dd does not return those two inputs, you know that the route is not correct or a middleware is intercepting the data. Update this answer in the comments with more info after your testing is done. Also I am not sure why you are trying to dd Auth:user. Of course it will return nothing. You have not logged in yet. There IS no user for it to show. Unless you have done something like:
$users = Users::firstOrCreate($data);
Auth::loginUsingId($users->id);
$users->save();
You have not actually saved any user in your database or logged in. I think you need to find a better tutorial to do this from.
I have a new installation of laravel 5.7
I have created the database and users table with dummy info manually and connected the database with the application.
Can anyone please point out why the following code isn't working.
login.blade.php
<div class="form box">
<h1 align="center">Login - MobileInfo</h1>
<br />
#if(isset(Auth::user()->username))
<script>window.location="main/success"</script>
#endif
#if ($message = Session::get('error'))
<div class="alert alert-danger alert-block">
<button type="button" class="close" data-dismiss="alert">x</button>
<strong>{{ $message }}</strong>
</div>
#endif
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
<form method="post" action="{{ url('login/checklogin') }}">
{{ csrf_field()}}
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" />
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" class="form-control" />
</div>
<div class="form-group">
<input type="submit" name="login" class="btn btn-primary" value="Login" />
</div>
</form>
</div>
</div>
Login Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator;
use Auth;
class LoginController extends Controller
{
public function index()
{
return view ('login');
}
function checklogin(Request $request)
{
$this->validate($request, [
'username' => 'required',
'password' => 'required'
]);
$user_data = array(
'username' => $request->get('username'),
'password' => $request->get('password')
);
if(Auth::attempt($user_data))
{
return redirect('login/success');
}
else
{
return back()->with('error', 'Wrong Login Details');
}
}
function success()
{
return view('dashboard');
}
function logout()
{
Auth::logout();
return redirect('login');
}
}
web.php
Route::get('/', 'LoginController#index');
Route::post('login/checklogin', 'LoginController#checklogin');
Route::get('login/success', 'LoginController#success');
Route::get('login/logout', 'LoginController#logout');
The error I see after adding any of the correct combinations of username/password is the else block of Auth::attempt($user_data), that is "Wrong Login Details".
Laravel store passwords using its hashing algorithm and then validate/compare with same hashing algorithm.
The problem is, you stored literal passwords in database, that's why laravel is unable to validate those passwords. Laravel is expecting hashed password from database.
Literal password won't work. So ...
#1
Best solution is, make a signup form as well (using laravel Auth) and insert demo data through that signup form. Laravel will store passwords after hashing it, and eventually successfully validating those passwords.
#2
Another(complex/tedious) solution is, find out laravel's hashing algorithm and hash passwords with a separate php script. Then store hashed passwords in database directly. You don't need signup form in this case because you are doing it manually.
Update for solution # 2
Use below code to hash your literal passwords in laravel 5.x.
$hashedpassword = bcrypt('plaintextpassword');
By default, Laravel auth provide authentification with email, so to use another field to login, you may define it in LoginController.
public function username()
{
return 'username';
}
Documentation
I am trying to implement a password reset on my Laravel 5.1 app. I have followed the docs (http://laravel.com/docs/5.1/authentication#resetting-passwords) to get this working. However whenever I click on my 'reset password' button on my /password/email/ no email is ever sent.
I have intentionally entered incorrect emails and I am getting the appropriate error however when I enter a correct email no email is sent and I get no type of message or any emails.
I have looked at my database and it does looks as though a password reset token being created, just no email is sent.
My email configuration is working properly as other parts of my application sends email properly, only this one section is not sending the emails. Any help will be appreciated as I do not what else to check.
Michael
routes.php:
`
// Password reset link request routes...
Route::get('password/email', ['as' => 'password/email', 'uses' => 'Auth\PasswordController#getEmail']);
Route::post('password/email', 'Auth\PasswordController#postEmail');
// Password reset routes...
Route::get('password/reset/{token}', 'Auth\PasswordController#getReset');
Route::post('password/reset', 'Auth\PasswordController#postReset');
password.blade.php:
<form id="contact-form" class="contact-section" method="POST" action="/password/email">
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
<span class="pre-input"><i class="fa fa-envelope-o"></i></span>
<input class="name plain buffer" type="email" name="email" placeholder="Email" value="{{ old('email') }}">
<input id="send" class="plain button yellow" type="submit" value="Reset Password">
#foreach($errors->all() as $error)
<font size="3" color="red">{{ $error }}</font>
#endforeach
</form>
resources/views/emails/password.blade.php:
Click here to reset your password: {{ url('password/reset/'.$token) }}
Update
I have added a Log to the postEmail function.
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$response = Password::sendResetLink($request->only('email'), function (Message $message) {
$message->subject($this->getEmailSubject());
Log::info('Password Reset Execute -1 '); //Does work here
});
switch ($response) {
case Password::RESET_LINK_SENT:
return redirect()->back()->with('status', trans($response));
case Password::INVALID_USER:
return redirect()->back()->withErrors(['email' => trans($response)]);
}
Log::info('Password Reset Execute - 2'); //Will not work here
}
I added those in .env and password reseting is working again
MAIL_FROM_ADDRESS=xx#xx.xx
MAIL_FROM_NAME=xxxx
If the issue is invalid sender, make sure you pass the correct sender
$message->from('hello#app.com', 'Your Application');
I am working on laravel 5 eCommerce web portal.
I am having an issue when the user updates the password using the ready made scripts.
The issue is that I can send the link to the customer perfectly without any issue and the customer can change his password also. But when logged out and re-logging in, I get the error as Invalid credentials.
In my routes.php, I have this:
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
This is the login page:
<form class="form-horizontal" role="form" method="POST" action="{{ url('/login') }}">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<div class="form-group">
<label class="col-md-4 control-label">E-Mail Address</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" value="{{ old('email') }}">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password">
</div>
</div>
<div class="form-group">
<div class="col-md-4"></div>
<div class="col-md-4">
Forgot Password
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary btn-block">Login</button>
</div>
</div>
</form>
I cannot login again after I am logged out once the password has been reset.
EDIT 1:
When the login button is clicked on the login form page, the postLogin method is called. Here's the code
public function postLogin( Request $request ) {
$this->validate( $request, [
'email' => ['required', 'exists:users,email,role,customer'],
'password' => 'required'
]);
$credentials = $request->only('email', 'password');
if ( \Auth::attempt($credentials) ) {
\Session::flash('logged_in', 'You have successfully logged in.');
return redirect('/');
}
return redirect('/login')->withInput($request->all())->withErrors(['email' => 'Invalid Email Address Or Password']);
}
EDIT 2:
I just realize that login is not checking for the hash and hence returning false, on doing dd(\Hash::check($request->password, $user->password)), after updating the password and re-logging in. What could be the issue with this ?
Where have I made mistake ? Kindly guide me.
Thanks in advance.
P.S.: I am using the defaults only to update the password, rest all, I have made the controllers and models which are all working fine without any issue.
I stumbled upon this as well and found the answer here, just adding this for future reference..
The reason is that as soon as you add the setPasswordAttribute method on your User model, the password is hashed twice when using the built-in password reset functionality of Laravel. As explained on the Laracast page, all it needs is a check for an already hashed password, eg:
// Add Hash facade
use Illuminate\Support\Facades\Hash;
class User extends Authenticatable
{
// ...
/**
* Automatically hash password
*
* #param String $value The password, maybe hashed already
*
* #return string|null
*/
public function setPasswordAttribute($value)
{
if ($value) {
$this->attributes['password'] = Hash::needsRehash($value) ? Hash::make($value) : $value;
}
}
}
If the new password does not work after changing then something goes wrong when changing the password.
Most likely suspect is the encryption. It can be possible that you are not using the Hash::make($password) and saving it in plaintext format.
You can doublecheck if the hash is saved correctly to DB with function Hash::check($password, $hash);
During the login you can check the password as
public function postLogin( Request $request ) {
$user=User::where('email', $request->email);
Log::debug("Testing $request->password $user->password ". Hash::check($request->password, $user->password));
}
If the Hash::check is false then something went wrong when saving new password. $user->password must be in hashed form.
I have 3 user types :
Admin
Distributor
Internal
I have a problem sign in as user type. ( Internal )
I can sign in when my user type is Admin.
I can sign in when my user type is Distributor.
BUT I can’t sign in when my user type is internal. Wired ????
I look through every single line of my code in my sign-in functions in my AccountController.php.
I didn’t notice any bug there. If you guys notice any bugs there -- please kindly let me know.
That will be a huge help for me.
Here is my Sign-In Functions
GET
public function getSignIn(){
return View::make('account.signin');
}
POST
public function postSignIn() {
$validator = Validator::make( Input::only('username','password'),
array(
'username' =>'required',
'password' =>'required'
)
);
if ($validator->fails()) {
return Redirect::route('account-sign-in-post')
->with('error','Username/Password Wrong or account has not been activated !')
->withErrors($validator);
}
// Remember Me
$remember = (Input::has('remember')) ? true : false ;
$auth = Auth::attempt(array(
'username' => strtolower(Input::get('username')),
'password' => Input::get('password'),
'active' => 1),
$remember);
// Keep track on log-in information of the user.
if(Auth::check()){
$user = Auth::user();
$user->last_logged_in = Input::get('created_at');
$user->logged_in_count = $user->logged_in_count + 1 ;
$user->is_online = '1';
$user->save();
}
if($auth) {
return Redirect::to('/')
->with('success','You have been successfully logged in.')
;
}
else {
return Redirect::route('account-sign-in')
->with('error','Username/Password Wrong or account has not been activated !')
->withInput(Input::except('password'))
->withErrors($validator);
}
}
VIEW
#extends ('layouts.form')
#section('content')
<style type="text/css">
.signin{
text-align: center;
}
#forgetpassword{
/*color:#5cb85c;*/
color:silver;
}
</style>
<form class="form-horizontal" role="form" action=" {{ URL::route('account-sign-in-post')}}" method="post" >
#if ($errors->has('username')){{ $errors->first('username')}} #endif
<div class="form-group">
<label for=""> Email </label>
<input placeholder="Email" type="text" class="form-control" required name="username" {{ ( Input::old('username')) ? 'value="'.e(Input::old('username')).'"' : '' }}>
</div><br>
#if ($errors->has('password')){{ $errors->first('password')}} #endif
<div class="form-group">
<label for=""> Password </label>
<input placeholder="Password" type="password" class="form-control" required name="password">
</div><br>
<br>
<button type="submit" class="btn btn-success btn-sm btn-block ">Sign In </button>
{{ Form::token() }}
</form><br>
<div class="col-lg-12 text-center">
<a id="forgetpassword" href="{{ URL::route('account-forgot-password') }}"> Forget Password </a> <br>
</div>
#stop
I am sure that I typed in the right username and password because I double check with my database.
It keep redirecting me back to my sign-in page.
with('error','Username/Password Wrong or account has not been activated !')
Can someone please tell me, if I did anything that I’m not suppose to ?
In your situation, you should check your auth variable in your Sign_In Function.
According to your code,
$auth = Auth::attempt(array(
'username' => strtolower(Input::get('username')),
'password' => Input::get('password'),
'active' => 1),
$remember);
Keep in mind that, these are things need to make sure
username must match the database
password must match the database
user active must be 1
If any of these fail, therefore, it STOP you from signing in.
Since, you're so sure about username and password, what about user active ?
Did you check to if it's 1 ?
If Not
on your set-password function or anywhere, where you normally set your user active.
just do this :
$user->active = '1';
$user->save();
Let me know if this work!!