Customising token response Laravel Passport - laravel

I am working on an API at the moment and have hit a brick wall. I am using Passport with the 'Password' grant type.
I want to return the user information with the access tokens, however, I am not sure how to.
Which class could I implement, edit or extend to get this?.
I would like this to be returned:
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "lalalalalal",
"refresh_token": "lalalallala",
"user": {
"username": "a username",
"user_type": "admin"
}
}
Thanks in advance.

The instructions on how to do this are hinted in the BearerTokenResponse class (part of the league/oauth2-server package).
Tested on Laravel 5.7.
1. Extend the BearerTokenResponse class, add the extra params you need in the response.
namespace App\Auth;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;
class BearerTokenResponse extends \League\OAuth2\Server\ResponseTypes\BearerTokenResponse
{
/**
* Add custom fields to your Bearer Token response here, then override
* AuthorizationServer::getResponseType() to pull in your version of
* this class rather than the default.
*
* #param AccessTokenEntityInterface $accessToken
*
* #return array
*/
protected function getExtraParams(AccessTokenEntityInterface $accessToken): array
{
return [
'user_id' => $this->accessToken->getUserIdentifier(),
];
}
}
2. Create your own PassportServiceProvider class and override the makeAuthorizationServer() method in order to pass in your own BearerTokenResponse class.
namespace App\Providers;
use App\Auth\BearerTokenResponse;
use Laravel\Passport\Bridge;
use League\OAuth2\Server\AuthorizationServer;
class PassportServiceProvider extends \Laravel\Passport\PassportServiceProvider
{
/**
* Make the authorization service instance.
*
* #return \League\OAuth2\Server\AuthorizationServer
*/
public function makeAuthorizationServer()
{
return new AuthorizationServer(
$this->app->make(Bridge\ClientRepository::class),
$this->app->make(Bridge\AccessTokenRepository::class),
$this->app->make(Bridge\ScopeRepository::class),
$this->makeCryptKey('private'),
app('encrypter')->getKey(),
new BearerTokenResponse() // <-- The class you created above
);
}
}
3. Add your provider to the providers array in config/app.php
/*
* Application Service Providers...
*/
App\Providers\PassportServiceProvider::class,
4. Exclude the passport package from laravel auto-discovery in composer.json
This stops the default PassportServiceProvider class from being loaded.
"extra": {
"laravel": {
"dont-discover": [
"laravel/passport"
]
}
},
Then run composer install.

Two steps.
1. Add a new route in your routes file.
// routes/api.php
Route::post('oauth/token', 'AuthController#auth');
Keep in mind this will change the route for getting the token from /oauth/token to /api/oauth/token.
2. Add the controller method.
<?php
// app/Http/Controllers/AuthController.php
namespace App\Http\Controllers;
use App\User;
use Psr\Http\Message\ServerRequestInterface;
use \Laravel\Passport\Http\Controllers\AccessTokenController;
class AuthController extends AccessTokenController
{
public function auth(ServerRequestInterface $request)
{
$tokenResponse = parent::issueToken($request);
$token = $tokenResponse->getContent();
// $tokenInfo will contain the usual Laravel Passort token response.
$tokenInfo = json_decode($token, true);
// Then we just add the user to the response before returning it.
$username = $request->getParsedBody()['username'];
$user = User::whereEmail($username)->first();
$tokenInfo = collect($tokenInfo);
$tokenInfo->put('user', $user);
return $tokenInfo;
}
}

Im using Multi-Auth with passport, so the previous answers didn't help me.
After hours of "googling" I found this answer (after-) middleware.
My middleware basically gets the result of Passport auth, checks if there is an Bearer inside and append more data to the content.
<?php
namespace App\Http\Middleware;
use Closure;
class AppendTokenResponse
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$content = json_decode($response->content(), true);
if (!empty($content['access_token'])) {
$content['moredata'] = 'some data';
$response->setContent($content);
}
return $response;
}
}
Now put the new Middleware in $routemiddleware at App/Http/Kernel.php
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'cors' => \App\Http\Middleware\Cors::class,
'multiauth' => \SMartins\PassportMultiauth\Http\Middleware\MultiAuthenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'oauth.providers' => \SMartins\PassportMultiauth\Http\Middleware\AddCustomProvider::class,
'append_auth' =>\App\Http\Middleware\AppendTokenResponse::class,
];
Then just register this middleware to Passport Routes in Providers/AuthServiceProvider.php
With Multiauth:
Route::group(['middleware' => ['oauth.providers','append_auth']], function () {
Passport::routes(function ($router) {
return $router->forAccessTokens();
});
});
I believe regular passport should be (not tested):
Route::group(['middleware' => ['append_auth']], function () {
Passport::routes();
});

Another better answer from the web
Custom Laravel Passport BearerTokenResponse
https://gist.github.com/messi89/489473c053e3ea8d9e034b0032effb1d

To add custom claims to your Passport token, here is a gist using Passport 8 with Laravel 6
https://gist.github.com/onamfc/0422da15743918e653888441ba6226ca

Related

Where to switch to other service depending on logged user field?

In laravel 9 app I try to switch to different service
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
if ($this->app->environment('local')) {
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
$this->app->register(TelescopeServiceProvider::class);
$this->app->register(\Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class);
}
// Error pointing at this line
$loggedUser = Auth::user();
if( $loggedUser->membership_mark === 'G') { // G=>Gold Membership
$this->app->bind('App\Interfaces\PageMembershipMarkStrategyInterface',
'App\Implementations\PageGoldMemberStrategy');
}
}
But I got error :
Target class [hash] does not exist. in...
Looks like register method is not proper place for app->bind when I need to get logged user.
But where have I to make this binding? In custom service provider? Im middleware ?
MODIFIED BLOCK :
I create a middleware with command :
php artisan make:middleware SetPageMembershipMarkService
and in app/Http/Kernel.php I added it :
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
// I added this line :
\App\Http\Middleware\SetPageMembershipMarkService::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
But I got error :
Illuminate\Contracts\Container\BindingResolutionException: Target [App\Interfaces\PageMembershipMarkStrategyInterface] is not instantiable while building [App\Http\Controllers\InformOnPageInStockController]....
I am not sure in which place of Kernel.php I have to add ref to PageMembershipMarkStrategyInterface ?
checking log it appears that my SetPageMembershipMarkService is not triggered before error...
MODIFIED BLOCK 2:
In file app/Http/Kernel.php I added my Middleware reference:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
// I set it AFTER auth
'setPageMembership' =>\App\Http\Middleware\SetPageMembershipMarkService::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminat`enter code here`e\Auth\Middleware\EnsureEmailIsVerified::class,
];
abd in routes/api.php :
Route::middleware('auth:api')->prefix('v1') /*->name('api.v1')*/ ->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
...
Route::middleware(['setPageMembership'])->group(function () {
Route::resource('/inform-on-page-in-stock', InformOnPageInStockController::class)->except(['edit', 'add']);
});
and I still got error :
Illuminate\Contracts\Container\BindingResolutionException: Target [App\Interfaces\InformOnPageInStockStrategyInterface] is not instantiable while building [App\Http\Controllers\InformOnPageInStockController].
Checking logs I do not find log message I set in SetPageMembershipMarkService middleware, so looks like it does
not set before my controllers...
What is wrong ?
You mentioned using of RouteServiceProvider. Which is correct syntax ?
File app/Http/Middleware/SetPageMembershipMarkService.php has lines :
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Auth;
class SetPageMembershipMarkService
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$loggedUser = Auth::user();
\Log::info(varDump($loggedUser, ' -1 SetPageMembershipMarkService $loggedUser::'));
$membershipMark = $loggedUser->membership_mark;
if( $membershipMark === 'S') { // G=>Silver Membership
app()->bind('App\Interfaces\InformOnPageInStockStrategyInterface',
'App\Implementations\HasNoInformOnPageInStockStrategy');
}
if( $membershipMark === 'G') { // G=>Gold Membership
app()->bind('App\Interfaces\InformOnPageInStockStrategyInterface',
'App\Implementations\InformOnPageInStockGoldMembersStrategy');
}
return $next($request);
}
}
But in log file I do not see any log message I have in this Middleware...
Thanks!
You will not be able to get Auth:user() data in Service Provder. Because service provider runs before Laravel sets the Auth data, you'll have to use some hacky methods to handle it.
I think better ways to handle data related to auth would be on middleware and not in Service Provider.
Additional explanations can be found on this questions answer Laravel - How to get current user in AppServiceProvider
EDIT for modifed block
Your middleware registration is wrong.
$routeMiddleware this array is used to register a custom middleware which you gonna use and define manually
For example:
protected $routeMiddleware = [
.....
// I added this line :
'setPageMembership' => \App\Http\Middleware\SetPageMembershipMarkService::class,
Then you gonna use this middleware in your route groups like:
Route::middleware(['auth', 'setPageMembership'])->group(function () {
Route::get('test', [TestController::class, 'test']);
});
If you want the middleware to run for all the routes it is better to add it in the $middleware array or if you want in the certain route group (web/api) then in the $middlewareGroups individual web and api array.
Adding the middleware in RouteServiceProvder also works if you want every route to have the middleware.
However, for your use case, authentication is required before binding. So, you will need auth middleware to fire first before you perform those bind actions. So adding the middleware to your route file like I showed above will be enough for your use case.

How to only allow Bearer token in API authentication?

When using $this->middleware('auth:auth') the user token can be passed as query string, request payload or bearer token: https://laravel.com/docs/5.8/api-authentication#passing-tokens-in-requests
I want to only allow authentication by bearer token. This means I don't want to allow authentication by query string or post request.
I tried to solve it by adding a middleware which just removes the api_token
public function handle($request, Closure $next)
{
$request->request->set('api_token', null);
return $next($request);
}
but no matter what I do
Route::group(['middleware' => ['auth:api', 'remove-api-token'],
or
Route::group(['middleware' => ['remove-api-token', 'auth:api'],
will always trigger auth:api first. So my approach does not work.
Any ideas how to deny GET/POST authentication for auth:api only?
One option would be to extend the existing tokenGuard and overwrite the getTokenForRequest() method to only accept the bearer token:
Create a new Guard:
"app\Services\Auth\BearerTokenGuard.php"
<?php
namespace App\Services\Auth;
use Illuminate\Auth\TokenGuard;
class BearerTokenGuard extends TokenGuard
{
/**
* Get the token for the current request.
*
* #return string
*/
public function getTokenForRequest()
{
return $this->request->bearerToken();
}
}
Define your new Guard within a service provider:
"app\Providers\AuthServiceProvider.php"
use App\Services\Auth\BearerTokenGuard;
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
Auth::extend('bearerToken', function ($app, $name, array $config) {
return new BearerTokenGuard(Auth::createUserProvider($config['provider']), $app['request']);
});
}
add your new guard driver to the guards config:
"config\auth.php"
'guards' => [
'api' => [
'driver' => 'bearerToken',
'provider' => 'users',
'hash' => false,
],
],
I have not tested this, but it should work, although it might need some modifications.

Laravel redirected you too many times error

I am trying to implement a simple role-based authentication system in Laravel 7, where I have an additional field on user table named 'role' of integer type, which can have two values - 0 for general users and 5 for the admins.
Any logged in user should be able to access the '/railway' page. Only admins should be able to access the '/admin' page. Admins should also be able to access the '/railway' page.
I am following this article and getting 'too many redirect' error: https://dev.to/kaperskyguru/multiple-role-based-authentication-in-laravel-30pc
Edit:
Sorry forgot to mention!
Everything is working perfectly for the non-admin users. They are being redirected to the '/railway' page after logging in alright, and also being redirected to this page if they try to access the '/admin page'.
The error is happening for the admins only. It is redirecting them to the '/admin' page after logging in alright, but showing the 'too many redirection' error. But admins can access the '/railway' page which is perfect.
Edit-3
I've added this on a git repository, if anyone is interested to reproduce the issue: https://github.com/rawhasan/laravel-auth-bug.git
Here is what I've done so far:
web.php
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/railway', 'RailwayController#index')->name('railway');
Route::get('/admin', 'AdminController#index')->name('admin')->middleware('admin');
Middleware Admin.php
namespace App\Http\Middleware;
use Auth;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (!Auth::check()) {
return redirect()->route('login');
}
if (Auth::user()->role == 0) {
return redirect()->route('railway');
}
if (Auth::user()->role == 5) {
return redirect()->route('admin');
}
}
}
Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'admin' => \App\Http\Middleware\Admin::class,
];
HomeController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
return view('railway');
}
}
AdminController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function index()
{
return view('admin.admin');
}
}
Edit - 2
I also have this on the LoginController.php
use Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo;
public function redirectTo() {
if (Auth::user()->role = 5) {
$this->redirectTo = '/admin';
return $this->redirectTo;
} else {
$this->redirectTo = '/railway';
return $this->redirectTo;
}
}
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
Any help sorting out the issue would be appreciated!
So in both user roles it requires authentication which means you could wrap your routes under default laravel auth middleware for that:
Route::middleware(['auth'])->group(function () {
Route::get('/railway', 'RailwayController#index')->name('railway');
Route::get('/admin', 'AdminController#index')->name('admin')->middleware('admin');
});
And your middleware should look something like:
use Auth;
use Closure;
class Admin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (Auth::user()->role == 0) {
return redirect()->route('railway');
}
if (Auth::user()->role == 5) {
return redirect()->route('admin');
}
return $next($request);
}
}
Fixed this with the help from another source. Removed the following code from the Admin Middleware and it worked perfectly:
if (Auth::user()->role == 5) {
return redirect()->route('admin');
}
Since I am redirecting the admins from the loginController, this redirect from the middleware was making the conflict.
I've also kept this code in web.php as suggested by Leo:
Route::middleware(['auth'])->group(function () {
Route::get('/railway', 'RailwayController#index')->name('railway');
Route::get('/admin', 'AdminController#index')->name('admin')->middleware('admin');
});
Thanks for the answers everyone!
Include the following value in config/admin.php file in the end of auth key. after 'remember' key.
// Redirect to the specified URI when user is not authorized.
'redirect_to' => 'auth/login',
// The URIs that should be excluded from authorization.
'excepts' => [
'auth/login',
'auth/logout',
'_handle_action_',
'auth/forgot-password',
'auth/reset-password'
],

How to create verification code session between controllers

I have 2 controller which are Verify Controller and Register Controller. To access the register page, I have added a custom middleware where super admin need to enter a code to access it which means only super admin have access to the registration form.
I have build the verification code form and inside the Verify controller, I have hard coded a code to test if user entered the same code. I also create a session variable on Verify Controller to store if success.
How my session works
If I go to superadmin/register then store session as empty.
If it matches, store session value as success.
Checking session
Finally check the session on middleware using if else condition.
If empty, redirect to verify page.
If not empty, redirect to register page and proceed to register new super admin.
The problem is, I still can directly access superadmin/register. It does not redirecting to verify page.
Verify Controller
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Session;
class SuperAdminVerifyController extends Controller
{
public function showVerifyForm()
{
return view('auth.superadmin-verify');
}
public function verify(Request $request)
{
// Validate the form data
$this->validate($request, [
'verifycode' => 'required'
]);
$code = "123";
$verifycode = $request->verifycode;
if ($code != $verifycode)
{
return redirect()->back()->with('status', 'Invalid Code');
}
else
{
Session::put('session_val', 'success');
return redirect()->route('superadmin.register');
}
}
}
Register Controller
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Session;
use App\Superadmin;
class SuperAdminRegisterController extends Controller
{
public function __construct()
{
$this->middleware('checksessionvar');
}
public function showRegisterForm()
{
return view('auth.superadmin-register');
}
protected function register(Request $request)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email',
'password' => 'required'
]);
if (Superadmin::where('email', '=', $request->email)->exists())
{
return redirect()->route('superadmin.register')->with('status', "Email already exists");
}
else
{
$admin = new Superadmin;
$admin->name = $request->name;
$admin->email = $request->email;
$admin->password = Hash::make($request->password);
$admin->save();
Session::flush();
return redirect()->route('superadmin.register')->with('status', "Successfull added to database. Please go to Super Admin login page.");
}
}
}
Custom Middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Session;
class CheckSessionVariable
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$getSession = Session::get('session_val');
if($getSession == null)
{
return redirect()->route('superadmin.verify');
}
else if($getSession == "success")
{
return $next($request);
}
}
}
Routes
Route::prefix('superadmin')->group(function() {
Route::get('/verify', 'Auth\SuperAdminVerifyController#showVerifyForm')->name('superadmin.verify');
Route::post('/verify', 'Auth\SuperAdminVerifyController#verify')->name('superadmin.verify.submit');
Route::get('/register', 'Auth\SuperAdminRegisterController#showRegisterForm')->name('superadmin.register');
Route::post('/register', 'Auth\SuperAdminRegisterController#register')->name('superadmin.register.submit');
Route::get('/login', 'Auth\SuperAdminLoginController#showLoginForm')->name('superadmin.login');
Route::post('/login', 'Auth\SuperAdminLoginController#login')->name('superadmin.login.submit');
Route::post('/', 'CompanyController#store_company')->name('superadmin.company.submit');
Route::get('/', 'SuperAdminController#index')->name('superadmin.dashboard');
Route::get('/logout', 'Auth\SuperAdminLoginController#logout')->name('superadmin.logout');
});
Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* #var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'checksessionvar' => \App\Http\Middleware\CheckSessionVariable::class,
];
}
You could probably cut down on a lot of the steps you're currently doing and use a Gate in the controller. The scenario you describe is similar to the example provided in the documentation:
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
return true;
}
});

Laravel 5.4 - Prefixing and applying two middlewares for a multi-tenant application's routes

I'd like to group /account/{account_id} as well as protect every route inside it with the auth middleware and a middleware that will check if the logged user has access to this account. Unfortunately it's not working.
Here is my code
web.php:
Route::group(['middleware' => 'auth'], function () {
Route::group(['prefix' => 'account/{account}', 'middleware' => 'userHasPermissionForAccount'], function() {
Route::group(['prefix' => 'posts'], function () {
Route::get('{post}', 'PostsController#index')->where([
'post' => '\d+'
]);
});
// more routes here...
});
});
app/http/kernel.php
// ...
protected $routeMiddleware = [
// ...
'userHasPermissionForAccount' => \App\Http\Middleware\UserCanAccessContent::class,
];
It don't even triggers the code inside my custom middleware and I don't understand why.
I would use policies (gates), since you can use policy as middleware.
$ php artisan make:policy AcccountPolicy
Register the policy in AuthServiceProvider:
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
Account::class => AccountPolicy::class, //Account is model, remember to import!
];
Inside policy file (app/policies/AccountPolicy.php), create method lets say "manage"
/**
* Determine if ....
*
* #param \App\User $current
* #param \App\Account $account
* #return bool
*/
public function manage(User $current, Account $account)
{
//return some logic here to check if $current is part of $account
}
And then use this policy as middleware:
Route::group(['prefix' => 'account/{account}', 'middleware' => 'can:manage,account'], function...

Resources