How can I disable auto login after registration in laravel 8? - laravel

In using laravel 8 with fortify so I don have
App\Http\Controllers\Auth\RegisterController
Thanks in advance

First you must create a controller preferably in app\Http\Controllers\Auth called RegisteredUserController, in this controller you must overwrite the method store of the class RegisteredUserController.
Copy the store method to your new controller and delete the line $this->guard->login($user);.
It should look like this:
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Fortify\Contracts\RegisterResponse;
class RegisteredUserController
extends \Laravel\Fortify\Http\Controllers\RegisteredUserController
{
public function store(Request $request, CreatesNewUsers $creator): RegisterResponse {
event(new Registered($user = $creator->create($request->all())));
return app(RegisterResponse::class);
}
}
Finally change the default /register path that points to your new controller.
Route::post('/register', 'Auth\RegisteredUserController#store');

Fortify will automatically login an user only if you return the user from the CreateNewUser class. Instead of returning the created user, throw an exception along with a flash message. Fortify will try to redirect you to the home page and will return you back to the login page as user is not authenticated showing you the flash message. Below is a peek at the process in the file App\Actions\Fortify\CreateNewUser.
public function create(array $input)
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email',
'max:255',
Rule::unique(User::class),
],
'password' => $this->passwordRules(),
])->validate();
$user = User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password'])
]);
event(new Registered($user));
flash('Registration successful! Awaiting approval from admin.')
->success()
->important();
throw new \Illuminate\Auth\AuthenticationException\AuthenticationException();
}
I think there might be other solution to hook into any of the Fortify events to do that even more gracefully.

Related

Assigning the role while user registration Laravel

I'm trying to make a register page with role as a radio button(consumer, supplier, Admin)
but it show me this error when I test the query in postman
Error: Class "App\Http\Models\Role" not found in file
my controller:
public function register(Request $request)
{
$request->validate([
'first_name'=>'required|string',
'last_name'=>'required|string',
'email'=>'required|string|unique:users',
'password'=>'required|string|min:6',
'phone_number'=>'required|string|min:10',
'role_name'=>'required|string'
]);
$role_a = $request->role_name;
if ($role_a == 'صاحب متجر'){
$role=Role::select('role_id')->where('role_name','صاحب متجر')->first();
$user->roles()->attach($role);
return response()->json($user);
}
elseif ($role_a == 'مشتري'){
$role=Role::select('role_id')->where('role_name','مشتري')->first();
$user->roles()->attach($role);
return response()->json($user);
}
$user=User::create([
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'email' => $request->email,
'password' => Hash::make($request->password),
'phone_number' => $request->phone_number,
]);
And my use statement:
use Illuminate\Http\Request;
use App\Http\Models\User;
use App\Http\Models\Role;
use Illuminate\Support\Facades\Hash;
And my route:
Route::post('/register','App\Http\Controllers\AuthController#register');
and this what I have in tables:
Note: I didn't use custom packages like spatie for example
Thank you for trying to help!
You miss adding the Request class as an argument into your method. Your method should look like this:
public function register(Request $request)
{
//after validation
$data = $request->validated();
}
Dont forget to add use Illuminate\Http\Request; in your use statement.

Is there a built-in way to remove account enumeration from registration?

I have created a new site using Jetstream and Inertia. Currently the application will return a "The email has already been taken." message if a user tries to register with an existing email. Notwithstanding timing analysis, I would like to keep the existence of user accounts private. Is there a way to keep the unique constraint on email but display the same outward behavior if someone registers with an existing email? Ideally, I would like to not create a second user, but email the existing user suggesting they reset their password or ignore the email.
I agree with Unflux about not changing this, but if you need to you could modify CreateNewUser.php located at app\Actions\Fortify\CreateNewUser.php and change the validation message or modify the process.
The create() method which is responsible for creating the new user looks like:
public function create(array $input)
{
//define custom messages
$customValidationMessages = {
'email.unique' => 'New Message',
}
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], //email validation rules here
'password' => $this->passwordRules(),
], $customValidationMessages)->validate(); //add the variable containing the custom message(s) here
return User::create([
'name' => $input['name'],
'email' => $input['email'],
'password' => Hash::make($input['password']),
'api_token' => Str::random(60),
]);
}
If you need to send the user an email or customize this further I suggest you look into implementing an "After Validation Hook" which you can read about here: https://laravel.com/docs/8.x/validation#after-validation-hook
Here's what worked for me:
Create a new validation Exception in app/Exceptions/ExistingUserException.php
namespace App\Exceptions;
use Illuminate\Validation\ValidationException;
class ExistingUserException extends ValidationException
{
}
Break validation into 2 steps in app/Actions/Fortify/CreateNewUser.php, throwing the extended ValidationException if the form is otherwise good
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255'],
'password' => $this->passwordRules(),
'terms' => Jetstream::hasTermsAndPrivacyPolicyFeature() ? ['required', 'accepted'] : '',
])->validate();
$validator = Validator::make($input, [
'email' => ['unique:users'],
], ['email.unique'=>'']);
if ($validator->fails())
{
throw new ExistingUserException($validator);
}
Create a new middleware in app/Http/Middleware/CatchExistingUser.php
<?php
namespace App\Http\Middleware;
use App\Exceptions\ExistingUserException;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\URL;
class CatchExistingUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next, $redirectToRoute = null)
{
$response = $next($request);
if ($response->exception && $response->exception instanceof ExistingUserException)
{
return $request->expectsJson()
? abort(403, 'Your email address is not verified.')
: Redirect::guest(URL::route($redirectToRoute ?: 'verification.notice'));
}
return $response;
}
}
Inject the middleware into all fortify routes via config/fortify.php
'middleware' => [CatchExistingUser::class, 'web'],
Remove the auth middleware from the verification page by overwriting the route in routes/web.php
use Illuminate\Http\Request;
use Laravel\Fortify\Contracts\VerifyEmailViewResponse;
...
Route::get('/email/verify', function (Request $request) {
$user = $request->user();
if ($user && $user->hasVerifiedEmail())
{
return redirect()->intended(config('fortify.home'));
}
return app(VerifyEmailViewResponse::class);
})
->name('verification.notice');
The custom exception is not ideal but it seems cleaner than testing the validator stored in the ValidatorException and then removing one message if there's more than one error. I think this would be needed to allow the validation of other fields while not leaking email uniqueness.

Laravel/Passport Do I really need to register Passport::routes() for a simple CRUD API?

I registered Passport::routes(); in the boot method of AuthServiceProvider, but I don't seem to be using any of the routes it registers.
Do I need them? What are they used for? Can't I just use my custom routes that map to a custom controller for login, register and logout methods?
(EDITED) No, you do not need to register Passport::routes() in AuthServiceProvider if you don't use them. The following custom controller logic (adapted from https://medium.com/techcompose/create-rest-api-in-laravel-with-authentication-using-passport-133a1678a876) will still register a new user and return a valid token using Passport's built-in OAuth2 server:
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
'retype_password' => 'required|same:password',
]);
if ($validator->fails()) {
return response()->json($validator->errors(), Response::HTTP_FORBIDDEN);
}
$user = User::firstOrCreate(
['email' => $request->email],
['name' => $request->name, 'password' => bcrypt($request->password)]
);
$response = [
'token' => $user->createToken('MyApp')->accessToken
];
return response()->json($response, Response::HTTP_CREATED);
}
In the example above, createToken($key) comes from the HasApiTokens trait included with Passport which will return the token, regardless of whether you register the routes. (Thanks to patricus for correcting my initial answer.)

Laravel post request route

enter image description hereI have a following Controller in php laravel:
// .....
class RegisterController extends Controller
{
//...
//...
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}
I use the following route:
Route::post('api/auth/register', 'Auth\RegisterController#create');
I am getting the following error: "Too few arguments to function App\Http\Controllers\Auth\RegisterController::create(), 0 passed and exactly 1 expected"
I need your help to pass Request parameters to my function (Form route properly)
Try changing your method parameter to Request $request
to obtain an instance of the current HTTP request via dependency
injection, you should type-hint the Illuminate\Http\Request class on
your controller method. The incoming request instance will
automatically be injected by the service container
and get the data from the request fields:
protected function create(Illuminate\Http\Request $request)
{
return User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
}
If you do not want to write all the Request namespace in the method parameter, add on the top of the file:
use Illuminate\Http\Request;
then, just use the name of the class:
protected function create(Request $request)
{
//...
}
You can do it in this way,
use Illuminate\Http\Request;
class RegisterController extends Controller
{
protected function create(Request $request)
{
$data = $request->all();
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}

Create Method on User Model (bcrypt)

After looking at the new laravel version 5.4 i notice when using "$user = User::create(request(['name', 'email','password']));" the password isnt automatically bcrypt the password, is it me, or isnt the password hashed by default on the model create method? I dont remember, but isnt supposed the method "create" already do this?
In User Model you need to add below function, for default password encrypted.
public function setPasswordAttribute($value)
{
if($value != ""){
$this->attributes['password'] = bcrypt($value);
}
}
As stated in the Laravel Docs
If you are using the built-in LoginController and RegisterController classes that are included with your Laravel application, they will automatically use Bcrypt for registration and authentication.
If you use RegisterController.php that is shipped in Laravel you don't need to Hash password manually else you need to use
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']), //<==encrypt here
]);
Check the register Controller here:
https://github.com/laravel/laravel/blob/master/app/Http/Controllers/Auth/RegisterController.php#L63
Try out the following.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\User;
class RegistrationsController extends Controller
{
public function store()
{
//validate the form
$this->validate(request(),[
'name'=> ['required', 'string', 'max:255'],
'email'=> ['required', 'string', 'email', 'max:255', 'unique:users'],
'password'=>['required', 'string', 'min:4', 'confirmed'],
]);
//create and save the user
$user =User::create([
'name'=>request('name'),
'email'=>request('email'),
//hash your password
'password'=>Hash::make(request('password'))
]);
//sign in the user
auth()->login($user);
//redirect to the homepage
return redirect()->home();
}
}

Resources