Laravel 5.5 reset password without email field - laravel

I've not come across a site that asks you to confirm your email address during a reset request, it seems like an unnecessary step, i want my users to be able to enter only password and password confirmation but no email.
I'm wondering if there is a solution for this, i'm thinking of a simple solution i will pass the user email address as parameter in the reset link like this
website.com/verify/{{reset_token}}/{{email}}
Then i will retrieve this email parameter and pass it to the hidden input value but i don't know how to attach the email address to the reset link.
If everyone knows any solution please let me know in the comments
Thanks for your help

I hope you are using the default Laravel routes which are...
// Don't forget to add the names to these routes.
Route::get('password/reset', 'Auth\ForgotPasswordController#showLinkRequestForm')->name('password.forgot.get');
Route::post('password/email', 'Auth\ForgotPasswordController#sendResetLinkEmail')->name('password.forgot.post');
Route::get('password/reset/{token}', 'Auth\ResetPasswordController#showResetForm')->name('password.reset.get');
Route::post('password/reset', 'Auth\ResetPasswordController#reset')->name('password.reset.post');
Then run
php artisan make:mail PasswordResetMail
Then in your User model, add this function
public function sendPasswordResetNotification($token)
{
Mail::send(new PasswordResetMail($this));
}
Then in PasswordResetMail, then in your constructor, you will get the user
public function __construct($user)
{
$this->user = $user;
}
then pass the user to the blade view along with the token, and then in your blade file, add the route
route('password.reset.get', ['token' => $token, 'email' => urlencode($user->email)]);
This will pass the email as
?email=useremail%40gmail.com // Should be urlencoded
Then, in your reset form, add it as
<input type="hidden" value="{{ urldecode(request()->get('email')) }}" name="email">
Should be good to go :)

Related

Laravel stuck on email/verify

I just applied the laravel email-verification and wanted to make sure my users are verified, before entering page behind the login.
I added the follwing code:
class User extends Authenticatable implements MustVerifyEmail
...
Auth::routes(['verify' => true]);
...
Route::get('management', function () {
// Only verified users may enter...
})->middleware('verified');
If a user registers he gets a note and an email to verify his mail. He clicks the button in the mail, gets verified and everything works perfectly well.
But I discovered another case:
If the user registers and won't verify his mail, he will always get redirected to email/verify.
For example if accidentally having entered a wrong email, he can't even visit the register page, because even on mypage.com/register he gets redirected to mypage.com/email/verify!
Is this done on purpose by Laravel? Did I miss something? Do I have to / is it possible to exclude the login/register pages from verification?
Thank you in advance
I have this issue before, I have this way to resolve that, if you want to customize it you can consider this way.
In LoginController.php you can add this a little bit code, I overwriting the default login method:
public function login(Request $request)
{
$this->validateLogin($request);
$user = User::where($this->username(), $request->{$this->username()})->first();
// 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 ($user->hasVerifiedEmail()) {
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);
}
You can overwrite and add a new parameter to the sendFailedLoginResponse too to let the method know when to redirect to email/verify page or just add else in $user->hasVerifiedEmail() if block to redirect him to email/verify page
EDIT:
You can delete $this->middleware('guest') in LoginController and RegisterController to make logged in user can go to register and login page, but it will be weird if someone who already logged in can login or register again.
I had the same problem and I solved it very user friendly... (I think!)
First: Inside View/Auth/verify.blade.php put a link to the new route that will clear the cookie:
My mail was wrong, I want to try another one
Second: On your routes/web.php file add a route that will clear the session cookie:
// Clear session exception
Route::get('/clear-session', function(){
Cookie::queue(Cookie::forget(strtolower(config('app.name')) . '_session'));
return redirect('/');
});
This will clear the cookie if the user press the button, and redirect to home page.
If this doesn't work, just make sure that the cookie name you are trying to forget is correct. (Use your chrome console to inspect: Application -> cookies)
For example:
Cookie::queue(Cookie::forget('myapp_session'));

How to hide login form after reaching the total of failed login attempts?

I want to hide the login form and display an error message instead, but I can't.
I tried to put the code below that rewrites the action on the controller that shows the form, but the method that checks for too many login attempts doesn't seem to work and never returns true.
public function showLoginForm(Request $request)
{
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request) ) {
$seconds = $this->limiter()->availableIn($this->throttleKey($request));
return view('auth.block', array(
'seconds' => $seconds
));
}
return view('auth.login');
}
I managed the authentication process with php artisan make: auth login controller is the default generated by Laravel, the only change is in the action that displays the form.
The function hasTooManyLoginAttempts() needs, in the $request, the username (usually the email) as a key to know if the user has reached his max login attempts.
If, in the $request, there is not the username with a value the function is unable to verify the user login attempts.
So you cannot really know who is the user that wants to get your login form, you know who is only after he submitted the form.
IMHO the only way could be to add a username parameter to the GET request but you shoud provide it with some workarounds: cookies, session etc.
Looking at Laravel's code, it checks for hasTooManyLoginAttempts based on throttleKey and maxAttempts.
The throttleKey is dependent on the user's email and IP address. So the output of the following code is something like: info#example.com|127.0.0.1 and that is your throttleKey.
protected function throttleKey(Request $request)
{
return Str::lower($request->input($this->username())).'|'.$request->ip();
}
Now Laravel gets the user's email (username) from $request->input($this->username()) when you send a POST request, which you don't have access to in the showLoginForm method because it's called on the GET request.
Anyway, if you want to block the login form you'll need to come up with your own unique throttleKey and then override the method. Say you want your throttleKey to be based only on the IP address - which is not recommended. Here's how you do it:
// In LoginController.php
protected function throttleKey(Request $request)
{
return $request->ip();
}

How can I redirect to step2 page after verify the email based on their role?

How can I redirect to a step2 page after verifying the email based on their role?
Because I have two user types, both after register their email and pass, they will get a verification email, after that clicking button it redirects to home instead it will go to /signup/employee/step2 or /signup/user/step2.
Can I ask some tips on how to redirect the user based on their role with their step2 to complete registration?
Well, its obvious you'll need some type of ACL (access-control). If your app, need just that specific part, you can add a new column in your user table, is_employee and make it bool.
After that just implement a new middleware.
However, I would personally go with https://github.com/spatie/laravel-permission it is way easier :)
Laravel exposes an Event when user verify his account, you can add a custom listener to it and redirect user where you want.
You need to do something like this:
// app/Providers/EventServiceProvider.php
protected $listen = [
'Illuminate\Auth\Events\Verified' => [ // Laravel event
'App\Listeners\RedirectUsers', // Your custom listener
],
];
run # php artisan make:listener RedirectUsers -e Illuminate\Auth\Events\Verified
// app/Listeners/RedirectUsers.php
public function handle(OrderShipped $event)
{
if(Auth::user()->hasRole('admin')) {
return redirect('/admin');
}
// ...
}

How to use the rule validation in FormRequest class?

I have a Company, where I like to validate the update request. Until now I validated the request inside the update() action but I like to move this to its own CompanyUpdateRequest.
In the validation I check of the uniqueness of the tax number but of course I like to allow the same tax number for the very company.
'tax_number' => [
'required',
'string',
Rule::unique('companies')->ignore($company->tax_number),
],
This works as long it is placed inside the action, where I have $company already:
public function update(Request $request, Company $company)
{
}
My question is now, how I get the company inside the CompanyUpdateRequest?
I know that I could put the ID of the company inside a hidden field in the form, send it along with the request, pull the company from DB ... but this feels kind of wrong. Does anybody have a better / another approach or idea?
Thanks a lot.
use route() method. Assume your route parameter name is company-
$this->route('company');
Note: parameter method inside route method needs to exactly same as url route parameter. In this case-
Route::post('yourUrl/{company}','SomeController#method');
You can pass any data through a form:
<input name="company_id" value="{{ $company->tax_number }}" type="hidden">
Then in the CompanyUpdateRequest class:
Rule::unique('companies')->ignore($request->company_id),
You can also change this rule to:
'companies' => 'unique:companies,company_id,' . $request->company_id,
You can get it with $this->route('paramName');
Rule::unique('companies')->ignore($this->route('company')),

How to forward argument for redirect::route->with when hitting an auth filter using Laravel?

I have the following problem:
After a user is created and the user has confirmed her email.
I would like the user to login,
I use the following code to do that:
Redirect::route('login-forward')->with('alert_message', ...)
the alert messages simply states that everything went well, and I would like her to login.
login-forward is protected with an before filter, that runs the actual login form,
When the user then logs in sucesfully, she is brought back to login-forward, whic then puts the user at her personal landing page.
the code for the route 'login-forward is:
Route::get('my-login', array(
'as' => 'login-forward',
'before' => 'auth',
function ()
{
$user = Auth::user();
switch ($user->role)
{
case 'Administrator':
return Redirect::route('admin_dashboard');
case 'FreeUser':
return Redirect::route('cs-dashboard');
default:
return Redirect::route('/');
}}));
the problem is, the ->with('alert_message',...) is not seen by the real login route called by the before filter.
How do I solve this?
The best approach is to let the user logs in automatically when the email is confirmed, if the user confirms the account creation then when you find that user is valid then you may log in that user using something like:
// $user = Get the user object
Auth::login($user);
Also you may use:
Session::put('alert_message', ...);
Redirect::route('login-forward');
Then when the user logs in for the first time, just get the message from Session using:
// Get and show the alert_message
// from session and forget it
#if (Session::has('alert_message'))
{{ Session::pull('alert_message') }}
#endif
So, when you pull the message from the Session to show it, the message will no longer be available in the Session or you may use Session::reflash() to flash the flashed session data for another subsequent request until you get in the page where you want to show the message.
The best choice is - you can make forward to login form without redirect from method of controller for url of personal page.
return Route::dispatch(Request::create('login'))->getOriginalContent();

Resources