Voyager and Jetstream: Login to Admin Panel leads to Dashboard Page - laravel

I just started my first Laravel project and try to combine Jetstream Authentification with Voyager Admin Panel.
First of all, I installed Jetstream on a fresh Laravel installation and it worked so far:
Afterwards, I tried to add Voyager to generate the CRUDs for my website and added a new user with
php artisan voyager:admin your#email.com --create
But whenever I tried to login through the url "../admin", I was redirected to "../dashboard" from Jetstream.
Even if I reentered "../admin" as URL, I was redirected. As long as I was logged in, I cannot enter the Voyager Backend.
So I guess it's some kind of routing / middleware issue, but I cannot find out which issue it is.
Within the web.php Routing file, there's only the basic stuff:
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Route::group(['prefix' => 'admin'], function () {
Voyager::routes();
});
Not sure if that's relevant, but my IDE recognizes Voyager:: as unknown class, even it works the same way on a different Laravel installation.
But from the look of it, I expected the Route::middleware() to redirect a logged in person which types the url "../dashboard" to the Dashboard view, but nothing more. Removing this Route also didnt help the problem, so I guess I was wrong.
But beside this, only the pure Voyager Routes are left, so I'm not sure where else I can look to solve this problem.

You can add custom responses on app/Http/Responses directory.
just make new responses called LoginResponse
then use this code
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* #param $request
* #return mixed
*/
public function toResponse($request)
{
$home = auth()->user()->is_admin ? '/admin' : '/dashboard';
return redirect()->intended($home);
}
}
Then, bind your LoginResponse in FortifyServiceProvider
You can use this code
<?php
namespace App\Providers;
// ...
use App\Http\Responses\LoginResponse;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// ...
$this->app->singleton(LoginResponseContract::class, LoginResponse::class);
}
}

i know that it to late but for other users who had the same problem.
first i installed jetstream
int .env file APP_URL=http://localhost:8000
i installed voyager with dummy data
i added manualy in table user_roles this ligne ( the admin )
INSERT INTO `user_roles` (`user_id`, `role_id`) VALUES ('1', '1');
and it work
you can see this video i found in youtube i think it will help you .
https://www.youtube.com/watch?v=UDYZx5uIwmQ

Related

Laravel auth RegisterController namespace causing issue with artisan route:list command [duplicate]

This question already has answers here:
Error “Target class controller does not exist” when using Laravel 8
(27 answers)
Closed 1 year ago.
When I run `php artisan route:list' I get an error it can't find the RegisterController from the auth scaffolding.
Illuminate\Contracts\Container\BindingResolutionException : Target class [App\Http\Controllers\Auth\RegisterController] does not exist.
at C:\xampp\htdocs\antheap\vendor\laravel\framework\src\Illuminate\Container\Container.php:805
801|
802| try {
803| $reflector = new ReflectionClass($concrete);
804| } catch (ReflectionException $e) {
> 805| throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
806| }
807|
808| // If the type is not instantiable, the developer is attempting to resolve
809| // an abstract type such as an Interface or Abstract Class and there is
Exception trace:
1 Illuminate\Foundation\Console\RouteListCommand::Illuminate\Foundation\Console\{closure}(Object(Illuminate\Routing\Route))
[internal]:0
2 ReflectionException::("Class App\Http\Controllers\Auth\RegisterController does not exist")
C:\xampp\htdocs\antheap\vendor\laravel\framework\src\Illuminate\Container\Container.php:803
Which makes sense considering the RegisterController.php file is in Controllers/Web/Auth/ and its namespace is namespace App\Http\Controllers\Web\Auth;
I'm guessing it's looking for the wrong place because of default routing in the illuminate framework. However all the other Auth controllers are functioning fine. I'm not keen on moving everything just to make the list route:list command happy, though I kinda need it not crashing right now to help fix some other issue.
I've changed the Auth helper in web.php and added the auth routes:
// helper class generating all routes required for user authentication
// (authentication, registration and password resetting)
Auth::routes(['verify' => true, 'register' => false]);
Route::get('/login', 'Auth\LoginController#showLoginForm')->name('login');
Route::post('/login', 'Auth\LoginController#login');
Route::get('/logout', 'LoginController#logout')->name('logout');
Route::group(['middleware' => 'auth'], function () {
Route::get('/password/confirm', 'Auth\ConfirmPasswordController#showConfirmForm')->name('password.confirm');
Route::post('/password/confirm', 'Auth\ConfirmPasswordController#confirm');
});
Route::post('/password/email', 'Auth\ForgotPasswordController#sendResetLinkEmail')->name('password.email');
Route::get('/password/reset', 'Auth\ForgotPasswordController#showLinkRequestForm')->name('password.request');
Route::post('/password/reset', 'Auth\ForgotPasswordController#reset')->name('password.update');
Route::get('/password/password/reset/{token}', 'ResetPasswordController#showResetForm')->name('password.reset');
Route::group(['middleware' => 'guest'], function () {
Route::get('/password/register', 'Auth\RegisterController#showRegistrationForm')->name('register');
Route::post('/password/register', 'Auth\RegisterController#register');
});
However, this still doesn't allow for route:list to work correctly. The weird thing is I can comment out routes from about and they would still work normally (I assume covered by the default ones). Using route:clear doesn't change anything.
I can also add or remove the Auth\ in front of the Controller name, this doesn't keep it from working , nor will it fix route:list
But the app is definitely using it because if I change the URI suffix (like 'login' to 'logintest', it will show that in the browser address.
One thing that I forget to mention is that in RouteServiceProvide.php I added the \Web namespace (I don't know how route:list deals with that?)
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* #return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace . '\Web')
->group(base_path('routes/web.php'));
}
This because I had to break up the route file at some point into multiple ones with their own namespaces. And I put the Auth inside the Web routes due to many of its routes using limited to no middleware.
Problem is that taking Auth from the web folder and namespace just breaks way more than just route:list.
Ok I solved it, but not in a pretty way by moving back all the auth controllers to the folder route:list was looking for and just adding another separate routing file solely for auth
RouteServiceProvider.php
protected function mapAuthRoutes()
{
Route::middleware('web')
// ->namespace($this->namespace . '\Auth')
->group(base_path('routes/auth.php'));
}
I commented out the \Auth namespace because with testing it didn't seem to work properly
And then routes/auth.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;
/*
|--------------------------------------------------------------------------
| Auth Routes
|--------------------------------------------------------------------------
|
*/
// helper class generating all routes required for user authentication
// (authentication, registration and password resetting)
// Auth::routes(['verify' => true, 'register' => false]);
Route::get('/login', 'App\Http\Controllers\Auth\LoginController#showLoginForm')->name('login');
Route::post('/login', 'App\Http\Controllers\Auth\LoginController#login');
Route::post('/logout', 'App\Http\Controllers\Auth\LoginController#logout')->name('logout');
Route::group(['middleware' => 'auth'], function () {
Route::get('/password/confirm', 'App\Http\Controllers\Auth\ConfirmPasswordController#showConfirmForm')->name('password.confirm');
Route::post('/password/confirm', 'App\Http\Controllers\Auth\ConfirmPasswordController#confirm');
});
Route::post('/password/email', 'App\Http\Controllers\Auth\ForgotPasswordController#sendResetLinkEmail')->name('password.email');
Route::get('/password/reset', 'App\Http\Controllers\Auth\ForgotPasswordController#showLinkRequestForm')->name('password.request');
Route::post('/password/reset', 'App\Http\Controllers\Auth\ForgotPasswordController#reset')->name('password.update');
Route::get('/password/password/reset/{token}', 'App\Http\Controllers\Auth\ResetPasswordController#showResetForm')->name('password.reset');
Route::group(['middleware' => 'guest'], function () {
Route::get('/password/register', 'App\Http\Controllers\Auth\RegisterController#showRegistrationForm')->name('register');
Route::post('/password/register', 'App\Http\Controllers\Auth\RegisterController#register');
});
I had to completely write out the paths for the controllers or it wouldn't work
And the namespace used in the auth controllers (which is also the file path):
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
I don't feel like this was the cleanest solution, and I would love to know why route:list doesn't seem to understand the namespacing used before. But at least it's working again now.

Laravel 8 jetstream stack inertia. Redirect to Home after Login, instead of users choice

What happens to me is that if the user puts the url: project.test/med, the system redirects to Login but then it does not redirect to dashboard but to med. In RedirectIfAuthenticated the expression Auth::guard($guard)->check() is not evaluated or at least in the Log it is not shown, so I am not able to identify what is happening.
/** RedirectIfAuthenticated.php */
public function handle($request, Closure $next, ...$guards)
{
$guards = empty($guards) ? [null] : $guards;
   Log::info($request);
   Log::info(Auth::user());
foreach ($guards as $guard) {
     Log::info(Auth::guard($guard)->check());
     Log::info(Auth::check());
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
      }
   }
  Log::info(Auth::check());
   Log::info('end');
return $next($request);
 }
/** web.php */
Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
return Inertia\Inertia::render('Dashboard');
})->name('dashboard');
Route::middleware(['auth:sanctum','verified'])->get('/med', function (Request $request) {
return Inertia\Inertia::render('Med');
})->name('med');
Go to config/fortify.php and modify this line:
'home' => RouteServiceProvider::HOME,
to:
'home' => function(){
//if you want to go to a specific route
return route('dashboard');
//or if you have a bunch of redirection options
if (Auth::user()->hasRole('admin')) {
return route('admin.dashboard');
}
else{
return route('guest.dashboard');
}
}
EDIT: Fortify now ships with a simpler way of doing this. See this answer for simplified way.
The RedirectIfAuthenticated middleware does not do what you think it does. This middleware checks to see if a user is authenticated when trying to access a route with the guest middleware attached to it. So after you login to the application and you try to access /login route, this middleware will intercept the request and redirect the user to the RouteServiceProvider::HOME path.
With that being said, at the time of this writing, Laravel Fortify does not offer the ability to easily modify where the user gets redirected after registering or logging in to the application. See issue for more info
To get this to work you will have to go through a few steps.
Step 1 - Create new LoginResponse class
Anywhere in your application create a LoginResponse class and implement Laravel\Fortify\Contracts\LoginResponse.
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class LoginResponse implements LoginResponseContract
{
/**
* #inheritDoc
*/
public function toResponse($request)
{
return $request->wantsJson()
? response()->json(['two_factor' => false])
: redirect()->intended(config('fortify.home')); // This is the line you want to modify so the application behaves the way you want.
}
}
Step 2 - Override the default Fortify Login Response
In this step you have to tell Laravel to use your login response instead of the default Fortify response.
<?php
namespace App\Providers;
use App\Http\Responses\LoginResponse;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->bind(
LoginResponseContract::class, // Contract is required in order to make this step work.
LoginResponse::class,
);
}
//...
}
Once you're done making the changes the user will be redirected to wherever you set it to be.
There is a simpler solution to this.
If you look in config/fortiy.php you will see the home variable is set to:
'home' => RouteServiceProvider::HOME,
This refers to a public const variable in app/Providers/RouteServiceProvider.php
So to redirect users to the home page after they login you can simply change the home variable:
public const HOME = '/';
Doing it this way is slightly less complex and saves you having to create a whole new login response class.
If the changes don't take effect straight away try running:
php artisan optimize
Just open fortify in the config folder
Search for 'home' => RouteServiceProvider::HOME
and replace it but your code logic and don't forget to add Auth facades
use Illuminate\Support\Facades\Auth;
like is :
'home' => function () {
$is_active = Auth::user()->is_active;
$role = Auth::user()->role;
if ($is_active == 1) {
if ($role== 1) {
return '/admin/dashboard';
} else {
return '/';
}
} else {
return '/login';
}
},

Laravel Policies registration return false on Voyager

I added Voyager to my project, which uses a policy to check if a user can view/edit a specific project.
When I try to open the Projects table from Voyager, I get a 403 error.
It seems that when I remove the policy from my "policies" array in AuthServiceProvider, I am able to access the projects table in Voyager just fine.
I tried adding in my policy a check on $user->role_id == 1 (check if user is admin), but still no success, even if I replace the response of the policy to true.
Any idea what the issue might be? Thanks
Edit:
Desired behavior: I want to restrict the user from editing/viewing projects that are not his, however I want the admin to be able to access all projects from Voyager.
I ended up fixing it by adding the policy that I am using on the Projects bread, and had to add browse, add, edit, delete and read methods returning true.
It seems that once you have a policy registered Voyager will pick it up so you need to tell it how it should behave.
<?php
namespace App\Policies;
use App\User;
use App\Project;
use Illuminate\Support\Facades\DB;
use Illuminate\Auth\Access\HandlesAuthorization;
class ProjectPolicy
{
use HandlesAuthorization;
/**
* Create a new policy instance.
*
* #return void
*/
public function __construct()
{
}
public function browse(){
return true;
}
public function add(){
return true;
}
public function delete(){
return true;
}
public function edit(){
return true;
}
public function read(){
return true;
}
public function access(User $user, Project $project){
return $project->owner_id == $user->id ;
}
}
Have you tried some basics steps like :
php artisan route:clear
composer dump-autoload

Laravel - 403 invalid signature on email verification

I have enabled Email verification on my laravel site.
If they dont do it immediatly, but after a day or two, the link times out.. and they land on a page with 403-invalid signature.
From there they cannot do anything else beside manually editing the link. this is the point where I already lost some registrations. Is there a way to:
a) make this timeout much longer
b) in case of timeout/error land on a page that actually makes sense to the user?
#Omer YILMAZ answears your "a)" call and I am answearing your "b)" call:
We should disable signed Middleware that validates the URL signature (expiration) and automatically shows 403 page for the verification route, and then we should create a custom logic to validate the URL signature doing whatever we would like if it is invalid (expired).
Laravel 5.7, 5.8, 6.x and 7.x
Changing Auth\VerificationController provided by Laravel:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\VerifiesEmails;
class VerificationController extends Controller
{
use VerifiesEmails {
verify as verifyTrait;
}
protected $redirectTo = '/';
public function __construct()
{
$this->middleware('auth');
// $this->middleware('signed')->only('verify'); <-- remove this: it is causing 403 for expired email verification URLs
$this->middleware('throttle:6,1')->only('verify');
}
public function verify(Request $request)
{
if (!$request->hasValidSignature()) {
// some custom message
}
else {
return $this->verifyTrait($request);
}
}
}
Laravel 8.x
Changing the example provided by Laravel:
use Illuminate\Foundation\Auth\EmailVerificationRequest;
use Illuminate\Http\Request;
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
if (!$request->hasValidSignature()) {
// some custom message
}
else {
$request->fulfill();
return redirect('/home');
}
})->middleware(['auth', /*'signed' <-- remove this*/])->name('verification.verify');
In laravel 5.8 or above add this lines to config/auth.php
'verification' => [
'expire' => 525600, // One year in minutes
],
The following solution worked for me. Go to the next folder, app/Http/Middleware, and edit the following file TrustProxies.php. Change protected $proxies; edit for the following protected $proxies = ‘*’;
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
protected $proxies = '*';

Laravel 5.2 - ServiceProvider boot not working

Trying to use service provider to set a variables throughout all views pages that #extends('layouts.app') but not working, first I show the codes below.
AppServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// Using class based composers...
view()->composer('layouts.app', function($view){
$view->with('current_user', Auth::user());
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
When I visit the page that calls {{$current_user}}, it shows the following error
ErrorException in 5a5612347179ad88a6d4ebacc5d911a184c1b4ed.php line 14:
Undefined variable: current_user (View: C:\xampp\htdocs\soyegg\resources\views\shops\edit\showroom.blade.php)
Went through a several questions solved in the website and checked the followings but still failed:
1. AppServiceProvider is in config.app (default by Laravel 5.2)
2. php artisan clear-compiled
3. php artisan optimize
4. check whether there is compiled.php and try to clear it mannually but there is in neither storage/framework nor vendor.
Please help!
I think your ServiceProvider is working fine, you only need to change the way you passing data to the view. I've tested it myself and I can confirm that passing data to a view which later will be included with #extends() won't work. Instead you can use another methods:
view()->share('current_user', Auth::user());
Or using wildcard:
view()->composer('*', function ($view) {
$view->with('current_user', Auth::user());
});
// wildcard with prefix
view()->composer('prefix.*', function ($view) {
$view->with('current_user', Auth::user());
});

Resources