Laravel Authentication Custom Rule - php

I'm working with laravel Auth. Trying to add new rule with email and password, if status(field in user model) is = 1 then he cannot login. I cannot find where should i add this. I was looking at middleware, guard.php AuthenticateUsers.php but did not found it..
Edit:
I've solved this by creating new middleware that checks for this field. Also it can be done with Auth::attempt

You can try as:
if (Auth::attempt(['email' => $email, 'password' => $password, 'status' => 1])) {
// The user is active, not suspended, and exists.
}
From the Docs
If you wish, you also may add extra conditions to the authentication query in addition to the user's e-mail and password.

Add this code to your LoginController:
/**
* Attempt to log the user with custom credentials into the application.
*
* #param \Illuminate\Http\Request $request
* #return bool
*/
protected function attemptLogin(Request $request)
{
$credentials = $this->credentials($request);
$credentials['status'] = 1; // Additional field you want to check
return $this->guard()->attempt(
$credentials, $request->filled('remember')
);
}
Here we add the status field as a part of checked credentials. If user has status not equal to 1, authentication will fail.
Works with Laravel5.6

Related

How ResetPasswordController works with password_reset table Laravel

The built-in controller for resetting the password Auth \ Reset Password Controller has the reset function
public function reset(Request $request)
{
$request->validate($this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($request, $response)
: $this->sendResetFailedResponse($request, $response);
}
Well, here we are working with the user and their incoming data. However, I can't understand where the work with the password_resets table (built-in) is going? After all, after password recovery, entries are added/deleted there. I think (maybe incorrectly) that this is implemented in the broker () method, but I can't find it in the hierarchy of traits, interfaces, and other classes.
Checkout /vendor/laravel/framework/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php
This is the default class that implements the TokenRepositoryInterface and is used by the /vendor/laravel/framework/src/Illuminate/Auth/Passwords/PasswordBroker.php.
Inside this class you can find all the actual functionality that handles the password resets including the table operations you mention. For example, one method you'll find is:
/**
* Create a new token record.
*
* #param \Illuminate\Contracts\Auth\CanResetPassword $user
* #return string
*/
public function create(CanResetPasswordContract $user)
{
$email = $user->getEmailForPasswordReset();
$this->deleteExisting($user);
// We will create a new, random token for the user so that we can e-mail them
// a safe link to the password reset form. Then we will insert a record in
// the database so that we can verify the token within the actual reset.
$token = $this->createNewToken();
$this->getTable()->insert($this->getPayload($email, $token));
return $token;
}

Verification before creating a user in RegistrationController

In this Laravel script, when a user puts his details for registration, Laravel first creates the user, then sends an email for verification, I, on the contrary, want this action:
I want after the user puts his details, Laravel sends the email verification and if the verification is successful, creates the user.
The RegistrationController:
<?php
namespace App\Http\Controllers\Auth;
use App\GeneralSetting;
use App\Service;
use App\ServicePrice;
use App\User;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default, this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* #var string
*/
protected $redirectTo = 'user/dashboard';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* 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|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'username' => 'required|string|alpha_dash|max:25|unique:users',
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return \App\User
*/
protected function create(array $data)
{
$general = GeneralSetting::first();
$code = str_random(6);
if($general->email_verification == 1){
$ev = 0;
send_email($data['email'], $data['name'], 'Verification'
,'Your code is'.':' . $code);
}else {
$ev = 1;
}
$api = str_random(30);
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'username' => $data['username'],
'password' => bcrypt($data['password']),
'verification_time' => Carbon::now(),
'verification_code' => $code,
'email_verify' => $ev,
'api_key' => $api,
]);
$services = Service::all();
foreach ($services as $service){
$servicePrice = new ServicePrice();
$servicePrice->category_id = $service->category_id;
$servicePrice->service_id = $service->id;
$servicePrice->user_id = $user->id;
$servicePrice->price = $service->price_per_k;
$servicePrice->save();
}
return $user;
}
}
When user sign up, the information which He provide is store in the users Table at least you set the $table property of the model to something else. And the fact of saving users informations in the tables is part of the user registration process. It seams weird the fact that you want to register the user only after he verify his email address. My advice It will be to not log the user after he signed up and redirect him to another page even if he try to login you will set the loggin condition to log only user who has his email address verified.
You should implement a feature similar to how password reset works.
You can leave your create method as is. There is also a register() function inside your RegisterController.
1. In that function you should override the part where the user gets logged in and instead you should redirect him to a page with a message saying that an email has been send and he needs to verify it.
Now as i see you send a code with the email.
2. You should also provide a link inside the email that redirects the user to a code submission page.
3. If you dont have a page like that you should create one. A blade file, a function to view it and a route on your web.php file to access it.
4. Inside that page you will have a <form> with one <input> field e.g. 'code' where its action will point to a function you will create e.g. validateCode() inside your RegisterController.
Then this functions job will be to check on the Users table for a user with a code same with the one provided from the request, if such a user exists then it will update the 'email_verify' field to 1 loggin in the user and redirect him to the panel, if not the it will redirect back to code submit view:
public function validateCode(Request $request)
{
$user = User::whereVerificationCode($request->get('code'))->first();
if($user){
$user->verify_email = true;
$user->update();
Auth::login($user);
return redirect()->route('home');
}else{
return redirect()->back();
}
}
Also it would be good if you change the code your are generating to a 9 or 10 digit one or even better to a hashed string for security reasons.

Insert data and Login in laravel

I am working on an assignment in laravel where I've an Application form. I want to submit application form with email, mobileNo, customerId etc.
What I want is to insert form data into users table and then user will be logged in with auto generated password and redirect to Customer's dashboard. Where will be a modal will be open and ask for add password.
On the other hand there is also a login page from where user can login as usual. The login functionality is working properly.
Can someone help me to achieve the above functionality. Thanks in advance.
**Data is : **
email='user#gmail.com'
mobile='9875425698'
customerId='CI10001';
ApplicationForm Controller Where I am getting data successfully
class ApplicationForm extends Controller
{
public function saveApplicationForm(Request $request){
return $request;
}
}
Add user by submiting form
$password = bcrypt('secret'); //add here random password
$user = new User();
$user->email = 'xyz#gmail.com';
$user->mobileNo = '123456789';
$user->customerId = '1245';
$user->password = $password;
$user->save();
after you insert raw on user table login by user id without password
Auth::loginUsingId($user->id);
Auth::loginUsingId($user->id,true); // Login and "remember" the given user...
by otherwise login with email and password
Auth::attempt(['email' => $user->email, 'password' => $password], $remember);
all action do in one method(action)
Following my comment:
In the RegisterController (App\Http\Controllers\Auth)
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'institution' => $data['institution'],
'password' => 'NOT_SET',
]);
}
Then create a middleware (e.g. php artisan make:middleware Must_have_password)
namespace App\Http\Middleware;
use Closure;
use Auth;
class Must_have_password
{
/**
* Verify if password is set, otherwise redirect to password-set page.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if ($user && $user->password !== 'NOT_SET') {
return $next($request);
}
else return redirect('/set-password');
}
}
Of course, you then need to create a password setting view and hook that to the /set-password route. As I said in the comment, you want to make sure that /set-password route is well protected because you don't want people hijacking accounts that way. The good thing about this approach (using NOT_SET) is that people can always use the password_reset infrastructure to reset their password if they don't do it initially.
This is a bit hacky, but because Laravel always encrypts the passwords, there is no way the value can become NOT_SET in another way. Alternatively, you could add a boolean to your user-model (something like Must_Reset) that redirects to the password-reset page.
You can also hook in the password-reset functionality of Laravel, look for 'One Time Password Laravel' (e.g. here).

Send reset link with Laravel Auth and encrypted user table

I have a laravel 5.4 installation and I always used the default Laravel Authentication guard to handle user authentication and, mainly, the password restore process.
Now I had to encrypt the email in the users table using the Elocryptfive library, so I also added email_hash field where the hash of the mail is stored in the db in order to easily retrieve users by their email.
I can easily authenticate users using the hash:
Auth::attempt([
'email_hash' => hash('sha256', $request->get('email')),
'password' => $request->get('password')]
, $remember);
What I can't get working is the password reset process. Is there a class to override in order to retrieve users by email_hash, then access the decrypted email and send the mail, without rewriting the whole password forgotten process?
I found a way to achieve this. I will answer my own question to provide a useful solution if someone else needs some help on the topic:
In your ForgotPasswordController.php, override the sendResetLinkEmail function:
/**
* Send a reset link to the given user.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*/
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
$hashed = hash('sha256', $request->get('email'));
$user = User::where('email_hash', $hashed)->first();
if (!is_null($user)) {
$response = Password::sendResetLink(
['email_hash' => $hashed]
);
} else {
$response = Password::INVALID_USER;
}
return $response == Password::RESET_LINK_SENT
? $this->sendResetLinkResponse($response)
: $this->sendResetLinkFailedResponse($request, $response);
}
In your ResetPasswordController.php, override the credentials function:
/**
* Get the password reset credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
return [
'email_hash' => hash('sha256', $request->get('email')),
'password' => $request->get('password'),
'password_confirmation' => $request->get('password_confirmation'),
'token' => $request->get('token')
];
}
Thanks to Mike Rodham for pointing out the right direction, I hope it helps someone.

Override Auth Forgot Password in Laravel 5.3

I am using built in laravel auth functionality.Its working fine.I am trying to override following two functionality.
1.send forgot password email using mandrill.
2.send verification email while registering account.
Can any one help me to solve this issue
My aim is to use mandril instead of default email
I can see auth built in methods but i didnt got idea how i can override that
trait ResetsPasswords
{
use RedirectsUsers;
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* #param \Illuminate\Http\Request $request
* #param string|null $token
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Reset the given user's password.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function reset(Request $request)
{
$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
As answered by Mahfuzal, Laravel comes with a bunch of mail drivers out of the box. So just update your .env file to use the right driver.
As for sending a verification email when creating an account, you just need to override the postRegister() function inside the Auth/AuthController like so:
public function postRegister(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$confirmation_code = str_random(30);
$newUser = new User;
$newUser->username = $request->username;
$newUser->email = $request->email;
$newUser->password = bcrypt($request->password);
$newUser->confirmation_code = $confirmation_code;
$newUser->save();
$data = array('confirmation_code' => $confirmation_code, 'username' => $request->username);
Mail::send('emails.verify', $data, function ($message) use ($newUser){
$message->to($newUser->email, $newUser->username);
$message->subject('Please verify your email address');
});
return redirect('/auth/login');
}
This will execute the above code when registering a user rather than what Laravel does default out of the box so just tweak it to your needs.
You then just need to create a function that will check the token and verify their account when they click the link. For that, I use something similar to what is explained here.
Laravel provides drivers for SMTP, Mailgun, Mandrill, Amazon SES,
PHP's mail function, and sendmail, allowing you to quickly get started
sending mail through a local or cloud based service of your choice.
Open your .env file and change following by your Mandrill credentials and then you're good to go.
MAIL_DRIVER=mandrill
MAIL_HOST=
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
You can create your own reset method in the controller that uses the trait to override the method in the trait.

Categories