Verification before creating a user in RegistrationController - php

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.

Related

Laravel 8 - Multi Auth with two diffirent registration form?

I'm using laravel breeze as auth scaffolding package I want to know How can I
create two diffirent registration form for two User Types here is a simple explanation of hwat I want to achieve:
resources/auth/developer :
developer-register.blade.php
resources/auth/designer :
designer-register.blade.php
if the Visitor choose to register as "developer" it will display a diffirent form. and same thing for if the Visitor choose to register as "designer" it will display a diffirent form with fields.
I wish you understand what I want to achieve with this easy explanation.
Ok, so i've not used laravel/breeze myself (yet) but it shouldn't be much different from doing it in standard Laravel!
Views
By default, it looks like the breeze scaffolding is going to hit a create() method on the RegisteredUserController which will return a single view like so:
RegisteredUserController.php
/**
* Display the registration view.
*
* #return \Illuminate\View\View
*/
public function create()
{
return view('auth.register');
}
You have a few options here:
Replace this view with another
Add some logic to change the view which is returned based on the request being made (you can inject a Request object into the route like any other)
public function create(Request $request)
{
if ($request->has('developer')) {
return view('auth.developer-register');
} else {
return view('auth.designer-register');
}
}
Keep the original auth.register view and handle the logic in the blade template.
Registration
The forms on each of your registration pages will have an action that points to a controller route. This will likely be the RegisteredUserController within which you will find a store() method that handles the creation of a User model.
RegisteredUserController.php
/**
* Handle an incoming registration request.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|confirmed|min:8',
]);
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]));
event(new Registered($user));
return redirect(RouteServiceProvider::HOME);
}
As you can see, this store() method is handling the creation of a User model and then authenticating it before redirecting the user to the home route.
What you could do, is check the request for the the requested user type and then use a switch statement to change the type of use being created.
switch ($request->get('user_type'))
case 'developer':
$user = Developer::create([ /* add details here */ ]);
break;
case 'designer':
$user = Designer::create([ /* add details here */ ]);
break;
Auth::login($user);
I hope this will at least inspire you with your own solution!

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).

Laravel Auth: These credentials do not match our records

I am really new to Laravel. And I am enjoying every bit of the framework. I have recently run into some problems with Authentication/Login.
User registration works fine, but when I try to login using the same credentials created during registration, the app throws up this error:
These credentials do not match our records
I have also looked in the users table within the database and all the fields from the registration form is captured. I am just wondering why the app fails to retrieve these from the database.
See below my LoginController code:
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Firebase\JWT\JWT;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| 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;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/dashboard';
// Get your service account's email address and private key from the JSON
key file
protected $service_account_email = "abc-123#a-b-c-
123.iam.gserviceaccount.com";
protected $private_key = "-----BEGIN PRIVATE KEY-----...";
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->service_account_email = config('services.firebase.client_email');
$this->private_key = config('services.firebase.private_key');
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
protected function credentials(Request $request)
{
$data = $request->only($this->username(), 'password');
$data['email_confirmed'] = 1;
return $data;
}
protected function authenticated(Request $request, $user)
{
$jwt = $this->create_custom_token($user,false);
session(['jwt' => $jwt]);
return redirect()->intended($this->redirectPath());
}
function create_custom_token(User $user, $is_premium_account) {
$now_seconds = time();
$payload = array(
"iss" => $this->service_account_email,
"sub" => $this->service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $user->ref_code,
"email" => $user->email,
"name" => $user->name,
"phone_number" => $user->phone_number,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $this->private_key, "RS256");
}
}
How can I get this solved?
I found a solution to my problem above!
Okay, apparently, the issue was with the app double hashing the passwords. I read from http://laravel.com/docs/5.1/authentication
From where it talks about the attempt method:
"If the user is found, the hashed password stored in the database will be compared with the hashed password value passed to the method via the array. If the two hashed passwords match an authenticated session will be started for the user."
So even if I pass the correct password in with the form the attempt method is calling bcrypt on my password sent in from the form. Once it is hashed it is not going to match the plan text password anymore.
So, instead of trying to remember to hash my passwords on save/update/db seeding, I just added an attribute mutator to the User class:
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
And voila! Issue solved
If you use this method to set password hashed
public function setPasswordAttribute($password)
{
$this->attributes['password'] = bcrypt($password);
}
Don't use hash or bcrypt method in controller or seeder to avoid hashed password twice, like this:
$admin = User::create([
'name' => 'Admin',
'username' => 'admin',
'email' => 'admin#admin.com',
'mobile' => '0123456789',
'role_id' => 1,
'status' => 1,
'email_verified_at' => Carbon::now(),
'bio' => 'Administrator',
'password' => 'admin',
]);
I also face this problem.
Lavarel by default hash your password, just change 'hash' to 'bcrypt' in RegisterController.php
protected function create(array $data)
{
return User::create([
'password' =>bcrypt($data['password']),
]);
}

Confirmation Code for a user won't work Laravel 5.2

So was able to create a user, no problem. I wanted to add a confirmation code to validate a users email. I was able to have the application send an email to a user with a link. One a user clicks that link it updates the database. Here's the problem this only works when the user is logged out. When they are logged in nothing seems to happen. I don't want to force a new user to log out and verify before he can log in. Anyway here is my AuthController:
protected function create(array $data)
{
$confirmation_code = str_random(30);
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
'schoolid' => $data['schoolid'],
'confirmation_code' => $confirmation_code,
]);
Mail::send('emails.verify', compact('confirmation_code'), function($message) {
$message->to(Input::get('email'), Input::get('username'))->subject('Verify your email address');
});
return $user;
}
/**
* Attempt to confirm a users account.
*
* #param $confirmation_code
*
* #return mixed
*/
public function confirm($confirmation_code) {
$user = User::where('confirmation_code', $confirmation_code)->first();
$user->confirmed = 1;
$user->confirmation_code = null;
$user->save();
return redirect('/');
}
}
I am just showing you the create and confirm methods. If you need more code just let me know. However, I believe my problem may be from this code. Thanks for the help
The AuthController applies the guest middleware to all the methods except logout. Check the constructor. The guest middleware redirects authenticated users away.

LARAVEL5 Custom login

I'm working in application which requires a custom login.
I've to follow this flow.
User will enter login page.
User submit login page.
Application will check if the user is in database
3.1 (If user not in database | it will send a request to a third-party and check if login succeeded)
3.2 If user is in database verify password.
Now i've done class for the third-party and the code will work as this
$third = new Libraries\ThirdParty();
$third->login($username, $password);
$third->login will return true if login succeeded.
Now the question is how to link this logic. with the laravel pre-defined function Auth::check()
When you install laravel, it comes with a default login, that uses a trait:
class AuthController extends Controller {
use AuthenticatesAndRegistersUsers;
/**
* Create a new authentication controller instance.
*
* #param \Illuminate\Contracts\Auth\Guard $auth
* #param \Illuminate\Contracts\Auth\Registrar $registrar
* #return void
*/
public function __construct(Guard $auth, Registrar $registrar)
{
$this->auth = $auth;
$this->registrar = $registrar;
$this->middleware('guest', ['except' => 'getLogout']);
}
}
this class use the trait for login stored in: vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers.php
you can overwrite the methods from this class to put your own logic, for example in the class AuthController you can define a new:
function postLogin(){
//your new logic for login
}
and it gonna respect your function instead the trait funcion.
anyway, the logic behind the postLogin from auth trait is:
public function postLogin(Request $request)
{
$this->validate($request, [
'email' => 'required|email', 'password' => 'required',
]);
$credentials = $request->only('email', 'password');
if ($this->auth->attempt($credentials, $request->has('remember')))
{ //this if validate if the user is on the database line 1
return redirect()->intended($this->redirectPath());
//this redirect if user is the db line 2
}
return redirect($this->loginPath())
->withInput($request->only('email', 'remember'))
->withErrors([
'email' => $this->getFailedLoginMessage(),
]);
//redirect again to login view with some errors line 3
}
you can do two things:
edit the trait itself (bad practice) to put your own logic
define your own postLogin function in AuthController and copy the logic but edit it with your own custom logic.
Edit
to be more conrete with your points:
User will enter login page: you can use the default login page that laravel gives you, or you can overwrite getLogin function and redircet to your own view.
User submit login page: the form action needs to be: {{ url('/auth/login') }} or whatever route you put to postLogin()
Application will check if the user is in database: in the code line 1
3.1 (If user not in database | it will send a request to a third-party and check if login succeeded): in the code line 3
3.2 If user is in database verify password: in the code line 2
custom login 100% wroking without auth
use Hash;
$data->password = Hash::make(($request->password)); Encript Password
public function requestEmployee(Request $request)
{
if ($data = AddEmployee::where('name', $request->name)->first()) {
$pass = Hash::check($request->password, $data->password);
if ($pass) {
echo "sucess";
} else {
echo "Password Not Valid";
}
} else {
echo "Username Not Valid" . "<br>";
}
}

Categories