switch DB before auth in laravel - php

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.

Related

Laravel always returning 302 on PUT

I created a Laravel REST API. My routes are auto-generated with Route::apiResource().
Authentication is set up using Passport and is working as intended.
Now I tried to implement an Admin role with a Middleware that I attach to store, update and delete in my Controller:
$this->middleware('admin-only', ['only' => ['store', 'update', 'delete']]);
I want my application to respond with 403 Insufficient permissions if the User is not an Admin.
For GET it is working as intended, but for PUT requests Laravel is always returning a Response with 302 Found.
AdminOnly Middleware
namespace App\Http\Middleware;
use Illuminate\Http\Response;
use Closure;
use Illuminate\Support\Facades\Auth;
class AdminOnly {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next) {
$user = Auth::user();
if (!$user->admin) {
return Response::create('Insufficient permissions', 403);
}
return $next($request);
}
}
I found my Error by throwing an Exception in constructor of Symfony\Component\HttpFoundation\RedirectResponse class (thanks to #jedrzej.kurylo) and examining the produced stack trace in laravels errorlog (storage/logs/laravel.log).
The AdminOnly middleware was never called, because I forgot to onclude the id in the request (/person instead of /person/{id}). This caused my default route to trigger and redirect to the application base.

Laravel 5.6 - check if user can create record based on request parameter

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.

Limit a view to only invited users Laravel Middleware

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.

Why is Laravel's App::getLocale() method inconsistent?

I'm using 2 languages in my Laravel 5.2 app. There is a simple password-reminder page I'm implementing currently, and for reasons unknown to me I have problems in sending the new-password email in the correct language.
Let's say I see the page in German. In the view of the page, I echo 2 values, using Facades:
echo App::getLocale();
echo Session::get('locale');
The page is served in German, so both values echo de.
Now, I enter an email address into the form and submit it. The input gets to a controller method and calls a library to send a new password to the user:
public function resetPassword() {
// Validate the input, retrieve the user...
Mailer::sendNewPasswordEmail($user); // Call to the library sending emails
}
Finally, in the library, I var_dump the same 2 values, like this:
public static function sendNewPasswordEmail($user) {
var_dump(App::getLocale());
var_dump(Session::get('locale'));
die;
}
In this case, Session::get('locale') still equals de, but App::getLocale() shows en.
Why, why, why?
In my email template, I'm using the Blade's #lang() directive. As far as I know, the directive checks the application locale to determine which translation to serve. In my case, the email is being sent always in English and I have no clue why App::getLocale() returns a different value in the view and during the next POST request I'm making.
This is not the first time this happens, btw. At times is seems that views "know" more about the actual application locale, than the controllers, models or libraries. Confusing.
Ideas?
Laravel 5.2 App_Locale is not persistent. the only way I've found to make locales work properlly is creating a middleware that calls App::setLocale() like this:
<?php namespace App\Http\Middleware;
use Closure;
use Session;
use App;
use Config;
class Locale {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
App::setLocale(Session::get('locale'));
return $next($request);
}
}
Register your middleware on Kernel.php
protected $middleware = [
.
.
.
'App\Http\Middleware\Locale'
];

How to Authenticate a user from a table rather than 'users' table in Laravel 5.1?

I am new to Laravel, and I am trying to authenticate a user from players table.
As we know Auth::attempt is used to authenticate a user, and by default it works for users table, and for users table it is working perfect. But now I want to authenticate another user (a player) from another table (players), but I am unable to find a solution.
I had the same requirement. I had two user tables users(for main website) and admins (for admin panel). For that to happen, I must authenicate admin user against admins table. I wanted to use stock authentication library. So, I made following middleware.
Of course I had separate login form for admin panel
<?php namespace App\Http\Middleware;
use Closure;
class ChangeUserToAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
\Config::set('auth.table', 'admins');
\Config::set('auth.model', 'App\DB\Admin\Admin');
\Config::set('session.cookie', 'admin_session');
\Config::set('session.path', '/admin/');
return $next($request);
}
}
All my routes within admin route group (i.e. domain.com/admin/**) were protected by this middleware. So essentially I changed authentication model and table for admin area.

Categories