Laravel6 - Email verification customization on multi-login platform - laravel

I am new to laravel. I am trying to implement email verification on my laravel6 project.
On my project, there're three user types named 'user' 'vendor' and 'admin'. I have prepared separate directories for each user type in 'Controllers' and each of them has their own Auth files (e.g. Directory 'App/Http/Controllers/Vendor/Auth' has its own VerificationController.php, etc). So far, I've successfully implemented registration and login/logout function for each type with separate table in my DB.
A issue popped up when I tried to implement email verification. When I tried to access to a page where email verification is required, 'Auth\VerificationController#show' method seemed to be called regardless of the user type.
I went over laravel source code and learned that within the process, router calls Illuminate/Routing/Router->emailVerification() method. And the emailVerification() method routes to 'Auth\VerificationController#show' regardless of the user type.
What I wanted to do is to route depending on user type (e.g. if 'vendor' tries to login, I want to call 'Vendor\Auth\VerificationController#show').
I don't come up with any idea how to do for that. Can anyone please give me any advice?
Illuminate\Routing\Router class
public function emailVerification()
{
$this->get('email/verify', 'Auth\VerificationController#show')->name('verification.notice');
$this->get('email/verify/{id}/{hash}', 'Auth\VerificationController#verify')->name('verification.verify');
$this->post('email/resend', 'Auth\VerificationController#resend')->name('verification.resend');
}
Thank you in advance.

Related

Target [Laravel\Fortify\Contracts\ResetsUserPasswords] is not instantiable

I am implementing the forgot password / password reset logic with Laravel 8 and Fortify for an SPA application.
When the /reset-password is called and if the data are all correct (email, password, password_confirmation, token), I get a server side error:
Target [Laravel\Fortify\Contracts\ResetsUserPasswords] is not instantiable.
The route is defined as follows in api.php:
Route::post('/reset-password', [NewPasswordController::class, 'store']);
Thanks for your help
I had the same issue in my API and I was able to resolve it.
Target [Laravel\Fortify\Contracts\ResetsUserPasswords] is not instantiable.
Laravel\Fortify\Contracts\ResetsUserPasswords is an interface, and Fortify (by default) has implemented the ResetsUserPassword Action which implements the interface.
All you need to get it working is to ensure this class App\Providers\FortifyServiceProvider::class is registered within the providers array of your application's config/app.php configuration file.
// ...
App\Providers\FortifyServiceProvider::class,
You need to register views, thats why this error is throwing. I was able to fix the issue by doing this.
Document: https://laravel.com/docs/8.x/fortify#registration
Please check this thread: target [Laravel\Fortify\Contracts\RegisterViewResponse] is not instantiable
Fortify::registerView(function () {
return view('auth.register');
});

Where to check if an User is logged in in a Laravel Application?

I've been using your advice and View::sharing all of my important data to all views. However, there is one issue I have encountered.
This code:
if(!Auth::guest()){
$user=Auth::user()->id;
}
else $user=0;
$temp=DB::select('query');
View::share('cartnumber', count($temp));
View::share('cartitems', $temp);
doesn't work when put in AppServiceProvider. Or better, it always sets $user=0, even if I am logged in. I thought it is because AppServiceProvider's boot function executes before the site checks if someone is logged in.
I then tried to use a BaseController with a construct function but that doesn't work either. The only solution that seems to work correctly is putting the code in every single Controller for every view! That actually works, which kind of confirms my theory.
But is there anywhere I can put this code without having to copy/paste it in every single Controller? Thanks in advance!
You'd likely want to put this code later in the request life cycle to guarantee an auth user because as others have mentioned middleware/session code has not occured during this part of the framework booting up. You could use a service class to call in all your controllers to avoid the copy pasting. Or If you'd like to achieve this using code in your service provider you could use a View Composer instead of a share this allows you to define a callback/or class that will be called right before the view is returned
view()->composer(['/uri-that-needs-data'], function ($view) {
if (Auth::check()) {
$cart = DB::query(...)->get();
$view->with('cartitems', $cart);
}
});
Check out https://laravel.com/docs/5.7/views#view-composers for more details.
Auth::user() will be empty until the session middleware has run.
The reason you can't access the user inside your service provider is because that code is run during the "bootstrapping" phase of the application lifecycle, when it's doing things like loading filesystem or cache drivers, long before the request is sent through response handlers (including middleware).
Once the application has been bootstrapped and all service providers
have been registered, the Request will be handed off to the router
for dispatching. The router will dispatch the request to a route or
controller, as well as run any route specific middleware.
Source: https://laravel.com/docs/5.7/lifecycle
If you don't want to copy/paste that code everywhere, then one place to put it is in custom route middleware. You can list it after the auth middleware to guarantee a logged-in user.
Edit: View composers are another really good option, as suggested by #surgiie. The reason these can be set up inside a service provider (unlike your example) is because the view composer registers a callback, but doesn't execute it until a much later stage in the application lifecycle.

Laravel - How to create authentication for API without database

I'm writing an app at the moment which makes use of web-sockets and therefore needs to keep track of its users somehow.
I don't really want my users to register. Before using the app they should choose a name and will get a JWT-Token for it. I don't want to save anything in a database. As these names can be non-unique I will probaply add an Id.
I'm trying to use tymon/jwt-auth": "^1.0.0-rc.3.
public function login()
{
$token = auth()->tokenById(1234));
return $this->respondWithToken($token);
}
For some reason the tokenById-Function seems to not be available.
Postman says: BadMethodCallException: Method Illuminate\Auth\SessionGuard::tokenById does not exist.
In my case i have clear the cache. Then its working fine

Is it possible to get Laravel user data from Vue JS?

i have a Laravel 5.4 application where i do all Authentication based logic through PHP and then redirect the user to a catchAll route when they are authenticated, and let VueRouter take it from there...
I'd like to also use Entrust because my app will have several types of users and some elements (like an Edit User button) will only be visible to some user Roles.
I might also want to implement specific permissions, like some Admins can edit user Permissions, while others do not.
The issue is, alright i'm in Javascript territory now, so how do i know what my current Auth user is? Setting a global JS variable for Auth::user doesn't seem like a good idea to me.
Perhaps i would instead pass just an ID, but how exactly without making it globally visible as a window variable?
I think you may create an auth/check API call, like this:
protected function check()
{
if(Auth::guard('api')->check()) {
return Auth::guard('api')->user();
}
return ['success' => false];;
}
And then get current user with this call.

Laravel Route Is not working because of Generic route

I am new to Laravel and learning just basic stuff. I am trying to create a new Route to create a user into database. So I created a Route like this -
Route::get('users/"create"', 'PagesController#create');
But I also have one Route for users trying to access their profile-
Route::get('users/{username}', 'PagesController#show');
Now when I try to access users/create it redirect me to show method instead of create method in controller. I am guessing this is because of generic nature of users/{username}. So my question is how to deal with such situation.
The order that you define routes is important. If you define your routes like this - in this order, it will work.
Route::get('users/create', 'PagesController#create');
Route::get('users/{username}', 'PagesController#show');
Note - I noticed you used 'users/"create"' - that is an error - it should be 'users/create' like in my example.
p.s. make sure you dont allow a user with the username called 'create' - or they will never be able to get to their profile page.

Resources