Custom Request class does not exist, yet it does? - php

I'm trying to figure out why my custom request class cannot be called by one of my methods.
I created my class with, php artisan make:request ValidateUserSecretRequest.
This created my custom request file in the Http/Requests folder as expected.
However, ValidateUserSecretRequest called within my Auth\LoginController.php, , I get Class App\Http\Controllers\Auth\ValidateUserSecretRequest does not exist.
Here's the controller, with unnecessary methods removed:
namespace App\Http\Controllers\Auth;
use Cache;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use App\Http\Requests\ValidateSecretUserRequest;
use App\Http\Controllers\Controller;
class LoginController extends Controller
{
use AuthenticatesUsers;
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function postValidateToken(ValidateUserSecretRequest $request)
{
// get user id and create cache key
$userId = $request->session()->pull('2fa:user:id');
$key = $userId . ':' . $request->totp;
// use cache to store token to blacklist
Cache::add($key, true, 4);
// login and redirect user
Auth::loginUsingId($userId);
return redirect()->intended($this->redirectTo);
}
And my custom request class:
namespace App\Http\Requests;
use Cache;
use Crypt;
use Google2FA;
use App\User;
use App\Http\Requests\Request;
use Illuminate\Validation\Factory as ValidatonFactory;
use Illuminate\Foundation\Http\FormRequest;
class ValidateUserSecretRequest extends FormRequest
{
/**
*
* #var \App\User
*/
private $user;
/**
* Create a new FormRequest instance.
*
* #param \Illuminate\Validation\Factory $factory
* #return void
*/
public function __construct(ValidatonFactory $factory)
{
$factory->extend(
'valid_token',
function ($attribute, $value, $parameters, $validator) {
$secret = Crypt::decrypt($this->user->google2fa_secret);
return Google2FA::verifyKey($secret, $value);
},
'Not a valid token'
);
$factory->extend(
'used_token',
function ($attribute, $value, $parameters, $validator) {
$key = $this->user->id . ':' . $value;
return !Cache::has($key);
},
'Cannot reuse token'
);
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
try {
$this->user = User::findOrFail(
session('2fa:user:id')
);
} catch (Exception $exc) {
return false;
}
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'totp' => 'bail|required|digits:6|valid_token|used_token',
];
}
}
I've tried:
composer dump-autoload
composer update
scratching my head multiple times
recreating the custom request with artisan with a different name, same problem
What the hell is going on here?

You have written "use App\Http\Requests\ValidateSecretUserRequest;" while you are using "ValidateUserSecretRequest" class, There is a typo.

Error in use App\Http\Requests\ValidateSecretUserRequest; You can check it again.

You get Class App\Http\Controllers\Auth\ValidateUserSecretRequest does not exist since it doesn't really exists. App\Http\Controllers\Auth\ prefix in the error means that it uses current namespace.
Look at ValidateUserSecretRequest - you should swap User and Secret to write correct class name.

You have the class name wrong
You have it as
App\Http\Requests\ValidateSecretUserRequest;
but actually it is ValidateUserSecretRequest

Related

Auth::check() works only in middleware laravel [duplicate]

I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.

Laravel UserPolicy always returns 403 no matter what

I have the following policy called UserPolicy.
I want only admin users to access/edit the users data, even though I have set the return value to true(for testing) I still get 403 response no matter what.
namespace App\Policies;
use App\Models\Auth\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function viewAny(User $user)
{
// return $user->admin();
return true;
}
}
I have registered the policy as follows
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\Auth\User;
use App\Policies\UserPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
User::class => UserPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
The following code is how I use it in the controller
if (Gate::denies('viewAny')) {
return response('Not Authorized!', 403);
}
You should use authorize() method in your controller and pass User class as the second parameter. It will point the request to the targeted policy.
authorize() method is by default provided by Illuminate\Foundation\Auth\Access\AuthorizesRequests trait in your base controller.
Your controller could be like below:
try {
$this->authorize('viewAny', User::class);
} catch (AuthorizationException $e) {
return response('Not Authorized!', 403);
}

Confer Session Storage

Very simple question that I can't find the answer for. I'm using Confer in my Laravel app and wish to alter the html that is stored in the session storage for each new message. I've made a few formatting changes to conversation messages in views\conversation.blade.php as well as views\confer.blade.php, but when a user submits a new message, that message is pushed with the original formatting. I can't for the life of me find where the html formatting is passed into the session so it can be pushed to the client.
Confer's SessionController.php
namespace DJB\Confer\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use Illuminate\Http\Request;
use Session;
use Response;
class SessionController extends Controller {
/**
* Store the conversation list HTML in the session so that it can be retained over page loads
*
* #param Request $request
* #return Response
*/
public function store(Request $request)
{
Session::put('confer_conversations', $request->input('html'));
return Response::json(['success' => true]); // required to persist the session
}
/**
* Update the requested conversations that have yet to blossom with a message
*
* This needs to persist over page loads otherwise recipient(s) will not be
* subscribed to the channel to receive any messages.
*
* #param Request $request
* #return Response
*/
public function update(Request $request)
{
if (Session::has('confer_requested_conversations'))
{
Session::push('confer_requested_conversations', (int)$request->input('conversation_id'));
} else {
Session::put('confer_requested_conversations', [(int)$request->input('conversation_id')]);
}
return Response::json(['success' => true]); // required to persist the session
}
/**
* Clear the open chat list and requested list
*
* #return Response
*/
public function destroy()
{
Session::forget('confer_conversations');
Session::forget('confer_requested_conversations');
return redirect()->back();
}
}
MessageWasSent
namespace DJB\Confer\Commands;
use Illuminate\Console\Command;
use Illuminate\Queue\InteractsWithQueue;
use DJB\Confer\Message;
use DJB\Confer\Confer;
use Push;
class MessageWasSent extends Command {
use InteractsWithQueue;
protected $message;
protected $confer;
public function __construct(Message $message)
{
$this->message = $message;
$this->confer = new Confer();
}
/**
* Handle the command.
*/
public function handle()
{
$conversation = $this->message->conversation;
$conversation->touch();
if ($conversation->isGlobal())
{
Push::trigger($this->confer->global, 'NewMessageWasPosted', $this->message->getEventData('global'));
} else {
Push::trigger($this->message->conversation->getChannel(), 'NewMessageWasPosted', $this->message->getEventData());
Push::trigger($this->message->conversation->getChannel(), 'UserStoppedTyping', ['user' => $this->message->sender->id]);
}
}
}
namespace DJB\Confer\Events;
class MessageWasSent {
public function __construct()
{
}
public function handle()
{
}
}

Extending Laravel base controller

I am a newbie in Laravel framework and I want to extend a base controller which in turn extends controller. However, I discovered that when I do that, my controller no longer recognises my session variables.
Here is my code
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends PermissionController
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
dd(session('userdata')['user_urls']);
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
And this is my PermissionController code
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Support\Facades\Gate;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PermissionController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct(Request $request) {
if(!session('userdata')['user_urls']->contains($request->path())){
dd(session('userdata')['user_urls']);
}
}
}
But I realize that my session('userdata')['user_urls'] becomes null at the PermissionController. But if I make FeeController to extend Controller, my session variables are intact.
I need to use the session variables for some control at the permission controller.
I am running Laravel 5.3 on a MAC OSX and PHP 7
I have figured out the problem. Actually, PermissionController is not registered in the web middleware group so that session is not persisting in the PermissionController. So the solution to your question is just make a trait named as Permission instead of the controller and use it in FeesContorller.
trait Permission{
public function permission(Request $request) {
if($request->session()->get('name') != null){
echo "Hello World";
}
}
}
And FeesController like this:
class FeesController extends Controller
{
use Permission;
public function index(Request $request)
{
$this->permission($request); // the method of the trait.
echo "\n".$request->session()->get('name');
}
}
Output:
If the name attribute is set in session then :
Hello World
Passion Infinite
Otherwise
No Output // null
I have solved the same problem with middleware. I have created a middleware that takes care of the authorization of requests by checking the session to ensure that the controller action being accessed is available in session.
This is the middleware
namespace App\Http\Middleware;
use Closure;
class PermissionMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$currentAction = \Route::currentRouteAction();
list($nothing,$route_action) = explode('App\Http\Controllers\\', $currentAction);
$user_actions=session('userdata')['user_urls'];
if((empty($user_actions))||!$user_actions->contains($route_action)){
return redirect('denied');
}
return $next($request);
}
}
This is the controller
namespace App\Http\Controllers\Settings;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Auth\PermissionController;
use App\Fee;
class FeeController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$data['title']="Fees";
$data['fees']=Fee::all();
return view('settings.fee.index',$data);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create(Request $request)
{
$data['title']='New Fee';
return view('settings.fee.create',$data);
}
So, instead of using the routes (cos of some other reasons), I used the controller actions.
So, once a user logs in, all the controller actions he can access are loaded into session. When he tries to perform any action, the middleware, does the check to ensure he is allowed to perform that action. Otherwise, he is routed away.
So, I either add 'permission' to the routes middleware or call
$this->middleware('permission')
on the controller's construct method.
That is working for me now.
Thank you everybody for your contributions.

Laravel 5.3 auth check in constructor returning false

I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.

Categories