I have a Laravel application that I have integrated with Xenforo so I can use Xenforo as the main user system behind the application. All of that is working properly, but my next challenge is trying to create middleware that takes the users' Xenforo permissions and restricts access to certain pages on the Laravel application.
I have a $user variable that I am passing to all of my views, and that contains all of the necessary user data that I need. I'm curious how I would go about accessing that same $user variable within my middleware to pull out their Xenforo permissions?
I have researched passing variables through the routes which I can access in the middleware. However, I am not looking to pass an actual parameter through the url to accomplish the task.
My BaseController contains the following and passes the $user variable to all of my views.
class BaseController extends Controller
{
public function __construct()
{
// Setting up the Xenforo enviornment
$dir = __DIR__;
require_once('../public/forum/src/XF.php');
\XF::start($dir);
$app = \XF::setupApp('XF\Pub\App');
// Retrieving the user_id of the current authenticated user
$session = $app->session();
$user_id = $session->get('userId');
// Looking up a users information by their user_id
$finder = \XF::finder('XF:User');
$user = $finder->where('user_id', $user_id)->fetchOne();
// Passing the user to every view
View::share('user', $user);
}
}
Here is the middleware and how I'm trying to get it to operate. My biggest issue is trying to get access to the $user variable that I am originally passing above.
class CheckRole
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
// I would like to find a way to access the $user variable here
if ($user->is_staff == true)
{
return $next($request);
}
else
{
//Restrict access and redirect
}
}
}
Using default Laravel users are accessible via the Auth::user() facade. The data there is filled via the Authenticate middleware.
In your case I'd suggest you use a similar strategy by implementing a middleware which logs the user in (the logic you now have in your controller) and then implement another middleware for checking roles. Beware when registering both middlewares, so the middleware which does the logging is executed first.
You could even go as far as to leverage the Auth facade yourself to manually log the user in and to store your custom user data like so.
You can do it by put your user data to session like this in your controller.
$session->put("user_data", $user);
access it from middleware
$app->session()->get("user_data");
Related
I am building an application, where there would be main application users (say support users) and separate client users (the application can have many different clients and each clients can have many users), every client has its own separate database, but the codebase for the entire application would be the same for every client.
What I wanted to achieve is, before calling auth in the main application, I wanted to call a middleware, which would detect a parameter (say db_slug) from request URL and according to that param it will change the DB respectively. And then login them to the client user to their respective DB.
Note: The client users will not be a part of the main DB. Their record would be only in their Client's DB.
But I am failing to do so, as my auth middleware is called first, before my custom middleware, and on accessing auth routes, it is saying unauthenticated, since that specific client user is not a part of my main application.
Note: I am using sanctum auth.
What I tried is, created a middleware called ClientDBMiddleware
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use DB;
use Config;
class ClientDBMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if($request->has('db_slug')){
$dbSlug = $request->db_slug;
DB::purge('mysql');
Config::set('database.connections.mysql.database', "db_$dbSlug");
}
return $next($request);
}
}
and applied it my api.php auth routes before auth middleware
Route::group(['middleware' => ['clientDB', 'auth:sanctum']], function () {
Route::get('/me', [UserController::class, 'me']);
});
Important Note :
If there is a better approach to achieve my required thing, then that would be highly appreciated, please help me with it.
I'm using the AppServiceProvider to share specific admin data with all related views.
Now I'd like to share admin data also with all admin related Controllers to replace Auth::guard('admin')->user()->firstname by $admin->firstname.
$id = Auth::guard('admin')->user()->id;
$admin = Admin::findOrFail($id)->first();
How can I share this piece of code with all related Controllers to get for example admin firstname via $admin->firstname?
I would go about creating a global middleware
php artisan make:middleware AdminCarrier
In the middleware, you can add the $admin variable to the $request bag and access it via the Controller.
class AdminCarrier
{
public function handle($request, Closure $next)
{
$id = Auth::guard('admin')->user()->id;
$admin = Admin::findOrFail($id)->first();
$request->request->add(['admin' => $admin]);
return $next($request);
}
}
In the controller, you can access it via:
$request->admin
Make sure the middleware is global by registering it at Http/Kernel.php
I am trying to implement a user registration system in Laravel 5.7 where I am facing an issue.
I have two tables for Users- Admin(created by copying default Laravel auth),
new routes, new middleware for admin. Every thing works fine while using guards.
I was trying to limit the user login by adding Approve/Disapprove functionality.
I added an extra column - admin(boolean) to the Users table.
In Login controller - LoginController.php Page, I added
protected function authenticated($request, $user)
{
if ( $request->user()->admin != 1)
// if($user->admin != 1)
{
return redirect()->route('approval');
}
else
{
return redirect('/engineer');
}
}
so that, when the admin is 1 I am directed to '/engineer' where as in other case I am directed to 'approval'.
It works as desired!.
Issue I am now facing is that if I try to access the 'engineer'
using user whose not approved I am able to access the page. I am not sure how to restrict it. The page is still restricted to public.
Since the controller will be accessed by both the user and admin, I used __construct in the controller
web.php
Route::resource('engineer', 'engineerController');
engineerController.php
public function __construct()
{
$this->middleware('auth:web,admin');
}
My Understanding is that the condition is only checked when the user logs in and there after its exits.
Do I need to create a new middle ware in order to keep the authorised page intact?
I am a self learner and new to laravel. I am pretty sure that I am not following the right practice. I started something and was trying to follow it till I finish. Please guide me through it.
Along with it please let me how could I have done it better.
You would need to define a Middleware that would check if the Engineer is approved or not.
Obviously, you would also need to keep that in an is_approved column for example.
<?php
namespace App\Http\Middleware;
use Closure;
class CheckEngineerApproval
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! auth()->user->is_approved) {
return redirect('user.approve');
}
return $next($request);
}
}
Then, add it in your $routeMiddleware array in your Kernel.
protected $routeMiddleware = [
//
//
'engineer.approved' => \App\Http\Middleware\CheckEngineerApproval::class,
];
Finally, you can add the Middleware in your Controller's constructor as well.
public function __construct()
{
$this->middleware(['auth:web','admin','engineer.approved']);
}
In my app users can create events that are categorised by a related organiser id.
I want to check if the user submitting a request to create a new event has access to the organiser they are creating the event for.
For example:
$organiser_id = $request->input('organiser_id');
if($user->hasOrganiser($organiser_id)) {
// User has permission
}
Obviously the above would work in my controller but ideally I would like to achieve this in my EventPolicy class or perhaps in the EventRequest.
Thanks in advance for your help.
Laravel provides many ways to go through this, you can always check the documentation, in the documentation you will find the checks in the controllers(which you can exclude), the model and in the middleware.
check the authorizing-actions-using-policies
you can always use a middleware which handles the HTTP requests before hitting your app isntance and hence much more control on your app.
Laravel includes a middleware that can authorize actions before the incoming request even reaches your routes or controllers. By default, the Illuminate\Auth\Middleware\Authorize middleware is assigned the can key in your App\Http\Kernel class.
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
Add it to the route file as the link explains so you can check the request and apply your guard.
Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Post');
you can check the model way as well in the first link.
I am traveling atm but I think this will help you.
Laravel uses a class called Auth so you can call that class staticky like: Auth::id()
More info:
https://laravel.com/docs/5.6/authentication
Hope this helps.
I am looking for a way to show a specific view only to specific visitors who get a link to that view. How can I make a middleware so that shows the view only if it comes from a specific source (like if it comes from source.blade.php)
I cannot use the middleware for guest or auth, because then it would give that view to all the auth, but I only want give that view to an auth who has made a payment at beginning and have been redirected from a specific URL.
How can I setup a middleware in such a way that it only shows the view if the auth is being redirected from another view like - source.blade.php
Currently, I have this page setted up like this
public function __construct()
{
$this->middleware('auth:client');
}
This works well, it only shows this page to someone who has logged in from the client authentication guard, but the problem is, any client can visit this page.
I am looking for a way to make it so that it can viewed only by the client who paid at the beginning, and were re-directed by my website. Maybe something like
public function __construct()
{
if(redirect_source="source.blade.php") {$this->middleware('auth:client'); }
}
I think you want a solution that will limit the permission based on your user type.
Middlewares are used to condition certain parameters if you want to let the requester to go into the specific url/route and not to control inside your views.
So if you want to control it, you can use this solution .
namespace App\Laravel\Middleware\Backoffice;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Auth, Session;
class ValidSuperUser {
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($this->auth->user()->type != "super_user") {
Session::flash('notification-status','failed');
Session::flash('notification-title',"Access Denied");
Session::flash('notification-msg','You are not allowed to view the page you are tring to access.');
return redirect()->route('backoffice.dashboard');
}
return $next($request);
}
}
in your Kernel.php under Http folder declare the new Middleware in order to use.
**put it under protected $routeMiddleware = []
and then use it to your routes that need to help that kind of user type.
$route->group(['middleware' => "aliasofyournewmiddle"],function(){
//some routes here
});
your new middleware can be any condition upon the request, so any inputs and available session that has been passed to that url are usable on that middleware, adjust it on how you want to handle the situation.
You can pass a token when redirecting your users to your specific page. Then use your middleware to check whether that token is valid or not.
Say for example, someone made a payment at beginning, you store a hash value of that person's user id or any unique identifier in a session, then redirect the user with the same hash value included in your url. Your middleware can then handle the validation, if the value stored in the session is the same with the value provided in the url.