yii2 Unable to verify your data submission - session

I use nginx, PHP 5.5.14, php-fpm, yii2, mac os.
I changed yii config to store session in database (postgress, user is superuser).
This is in my config:
'session' => [
'class' => 'yii\web\DbSession',
'sessionTable' => 'session',
],
And now when I try to register new user I've got this error:
Bad Request (#400)
Unable to verify your data submission
Here is a part of log:
10 17:25:57.434 info yii\db\Command::query SELECT "data" FROM "session" WHERE "expire">1425993957 AND "id"='cfg9sutufqchr1tdose4cack15'
/Users/pupadupa/Dev/www/mint-office-web/components/Controller.php (41)
11 17:25:57.442 info yii\web\Session::open Session started
/Users/pupadupa/Dev/www/mint-office-web/components/Controller.php (41)
12 17:25:57.450 error yii\web\HttpException:400 exception 'yii\web\BadRequestHttpException' with message 'Не удалось проверить переданные данные.' in /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/web/Controller.php:110
Stack trace:
#0 /Users/pupadupa/Dev/www/mint-office-web/components/Controller.php(41): yii\web\Controller->beforeAction(Object(app\controllers\user\RegistrationAction))
#1 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Controller.php(149): app\components\Controller->beforeAction(Object(app\controllers\user\RegistrationAction))
#2 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Module.php(455): yii\base\Controller->runAction('registration', Array)
#3 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/web/Application.php(83): yii\base\Module->runAction('user/registrati...', Array)
#4 /Users/pupadupa/Dev/www/mint-office-web/vendor/yiisoft/yii2/base/Application.php(375): yii\web\Application->handleRequest(Object(yii\web\Request))
#5 /Users/pupadupa/Dev/www/mint-office-web/web/index.php(20): yii\base\Application->run()
#6 {main}
13 17:25:57.454 trace yii\base\Controller::runAction Route to run: index/error
BTW,
I've got <?= Html::csrfMetaTags() ?> in head section and I have csrf input in my form. So it seems not the problem
I don't want to do public $enableCsrfValidation = false; because I think it's not solution but workaround.
How could I understand what cause this error?
As I mentioned earlier problem only appears when I store session in database.
Some additional information:
I could set and get variable from session. For example, I put it in beoreAction of Controller.php
Yii::$app->session->set('test', 'qwe');
$t = Yii::$app->session->get('test') ;
var_dump($t);
But after that If I comment first line like this
//Yii::$app->session->set('test', 'qwe');
$t = Yii::$app->session->get('test') ;
var_dump($t);
and refresh the page - I recieve NULL (BTW I could see Cookie:PHPSESSID=cfg9sutufqchr1tdose4cack15 in cookies after refresh).
So it seems there are some problems with session (DbSession) or maybe my php/php-fpm/nginx settings.
My UserController.php:
<?php
namespace app\controllers;
use app\components\Controller;
use app\models\Client;
use app\models\User;
use yii\filters\AccessControl;
use yii\web\BadRequestHttpException;
use yii\web\NotFoundHttpException;
class UserController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'employee'],
'rules' => [
[
'actions' => ['logout',],
'allow' => true,
'roles' => ['#'],
],
[
'actions' => ['employee', 'employee_add'],
'allow' => true,
'roles' => [ROLE_CLIENT_ADMIN],
],
],
],
];
}
public function actions()
{
return [
'login' => 'app\controllers\user\LoginAction',
'logout' => 'app\controllers\user\LogoutAction',
'restore' => 'app\controllers\user\RestoreAction',
'registration' => 'app\controllers\user\RegistrationAction',
'employee' => 'app\controllers\user\EmployeeAction',
'employee_add' => 'app\controllers\user\EmployeeAddAction',
//'passwd' => 'app\controllers\user\PasswdAction',
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV === 'dev' ? 'testme' : null,
],
];
}
/**
* #param int $clientId
* #return Client
* #throws BadRequestHttpException
* #throws NotFoundHttpException
*/
public function getClient($clientId)
{
if (!\Yii::$app->user->can(ROLE_ADMIN)) {
/* #var User $user */
$user = \Yii::$app->user->identity;
$clientId = $user->client_id;
}
if (!$clientId) {
throw new BadRequestHttpException('Bad request');
}
$client = Client::find()->where(['id' => $clientId])->one();
if (!$client) {
throw new NotFoundHttpException('Компания не найдена');
}
return $client;
}
}
My RegistrationAction.php:
<?php
namespace app\controllers\user;
use app\models\UserConfirm;
use Yii;
use app\components\Action;
use app\forms\RegistrationForm;
use yii\web\NotFoundHttpException;
class RegistrationAction extends Action
{
public function run($key = null)
{
if ($key !== null) {
/* #var UserConfirm $confirm */
$confirm = UserConfirm::find()->andWhere('expire > NOW()')->andWhere([
'key' => $key,
'action' => 'reg'
])->one();
if (!$confirm) {
throw new NotFoundHttpException('Key not found');
}
$user = $confirm->user;
$user->enabled = true;
$user->last_login = date('Y-m-d H:i:s');
$user->save();
$confirm->delete();
Yii::$app->user->login($user, 0);
return $this->controller->goHome();
}
$model = new RegistrationForm();
if ($model->load($_POST) && $model->validate() && $model->register()) {
$subject = Yii::$app->name . ' - Success';
$message = $this->controller->renderPartial(
'//email/registration',
[
'username' => $model->email,
'password' => $model->password,
'key' => $model->key,
'keyExpire' => $model->keyExpire
]
);
$res = Yii::$app->mailer->compose()
->setTo($model->email)
->setFrom([Yii::$app->params['from'] => Yii::$app->params['fromName']])
->setSubject($subject)
->setHtmlBody($message)
->send();
Yii::$app->session->setFlash('registrationFormSubmitted');
return $this->controller->refresh();
}
return $this->controller->render('registration', ['model' => $model]);
}
}

Looks like your session id changes. Check if the value of the session cookie changes after a second request. This happens when you misconfigure the domain that is set for the session cookie, make sure it matches the hostname in your URL.

I think this happens atimes when the server is messed up, all I needed to do was to restart my apache server.
For apache on MacOSx
sudo apachectl restart
For apache on Linux
sudo service apache2 restart
or
sudo service httpd restart

i hv used this while calling logout
$menuItems[] = [
'label' => 'Logout (' . Yii::$app->user->identity->username . ')',
'url' => ['/site/logout'],
// 'linkOptions' => ['data-method' => 'get']
'data-method' => 'get'
];
in main .php change post to get
---------------------------------------------------
and have changes this also
$url = Html::a('Logout',
['/site/logout'],
['class' => 'btn btn-success', 'data-method' => 'get']);
this is also in main.php
--------------------------------------------------------------------
in behaviour of site controller also
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup','index'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout','index'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['get'],
],
],
];
}
change post to get...and it will work....

What I did is, I just make the "csrfParam" different for both backend and frontend and after "php init" command everything is now working fine.
Not sure whether its a bug or we must have to set different "csrfParam" in case if we use DBsession.

Not sure if it's late, but I found this solution which worked for me in a similar case of Yii2 framework spitting 400 Bad Request at POST form requests.
Simply add this code in your form to manually include a CSRF input field for the key and Yii2 will accept the data submission:
<?php
use Yii;
echo Html::tag('input', '', ['type' => 'hidden', 'name' => '_csrf-backend', 'value' => Yii::$app->request->getCsrfToken()]);
?>
Note: this is for the advanced template. In the long run I suggest not to use a framework that bases on short tags as PHPers would know its a curse.

Related

cURL Error: Operation timed out after 15001 milliseconds with 0 bytes received woocomerce API

Facing cURL Error: Operation timed out after 15001 milliseconds with 0 bytes received issues with Woocomerce API to create products.
I am using the Laravel package i.e https://github.com/Codexshaper/laravel-woocommerce
It was working fine and creating products but suddenly it stopped working and start throwing PHP errors.
Below are the method that I am using to create a book on Woocomerce from laravel Controller:
public function addProductToWC(Request $request)
{
set_time_limit(0);
$response = '';
if ($request->isMethod('post')){
if(!empty($request->get('book_id'))){
$book = Book::find($request->get('book_id'));
$coverImgPath = base_path('public/customize_book/'.Session::get('cover_image'));
if (file_exists($coverImgPath)) {
$imageurl = url('/public/customize_book/'.Session::get('cover_image'));
} else {
$imageurl = url('/images/'.$book->bookimage);
}
if(!empty($book->id)){
$data = [
'name' => $book->title,
'type' => 'simple',
'regular_price' => number_format($request->get('book_price')),
'description' => (!empty($book->description) ? $book->description :''),
'short_description' => 'Simple product short description.',
'categories' => [
[
'id' => 1
]
],
'images' => [
[
'src' => 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_2_front.jpg'
],
[
'src' => 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_2_back.jpg'
]
]
];
$product = Product::create($data);
if($product['id']){
$response = array('error' => false,'code' => '200', 'data' => array('product_id' => $product['id'], 'message' => 'Product created successfully.'));
}else{
$response = array('error' => true,'code' => '401', 'data' => array('product_id' => $product['id'], 'message' => 'Product syncing failed please try again later.'));
}
}else{
$response = array('error' => true,'code' => '401','message' => 'Invalid book detail please try again.');
}
}else{
$response = array('error' => true,'code' => '401','message' => 'Invalid book detail please try again.');
}
}else{
$response = array('error' => true,'code' => '401','message' => 'Invalid method please try again.');
}
// return response
return response()->json($response);
}
Looking at the composer.json at https://github.com/Codexshaper/laravel-woocommerce/blob/master/composer.json, I can see that they are using the woocommerce client "automattic/woocommerce": "^3.0" This defaults to a request timeout of 15 seconds, hence why set_time_limit(0); didn't fix the issue.
When using it directly you'd set the timeout in the options
$woocommerce = new Client(
env('MGF_WOOCOMMERCE_API_URL'), // Your store URL
env('MGF_WOOCOMMERCE_API_KEY'), // Your consumer key
env('MGF_WOOCOMMERCE_API_SECRET'), // Your consumer secret
[
'timeout' => 120, // SET TIMOUT HERE
'wp_api' => true, // Enable the WP REST API integration
'version' => 'wc/v3' // WooCommerce WP REST API version
]
);
Looking at the library source https://github.com/Codexshaper/laravel-woocommerce/blob/master/src/WooCommerceApi.php
$this->client = new Client(
config('woocommerce.store_url'),
config('woocommerce.consumer_key'),
config('woocommerce.consumer_secret'),
[
'version' => 'wc/'.config('woocommerce.api_version'),
'wp_api' => config('woocommerce.wp_api_integration'),
'verify_ssl' => config('woocommerce.verify_ssl'),
'query_string_auth' => config('woocommerce.query_string_auth'),
'timeout' => config('woocommerce.timeout'),
]
);
It looks like the timeout is coming from woocommerce.timeout in your Laravel config file.

Laravel LDAP (Adldap2) Can't authenticate,username is null into guard->attempt

Morning,
I keep getting the message "A username must be specified." when trying to login my app.
Connection to LDAP is OK, sync also, in my database/table users i see all username with password.
But can't login with anyone username.
Trying to dd($username) into LoginController, "guard()->attempt" show me "null".
Thanks for your help !
My version
Laravel Version: ^7.0
Adldap2-Laravel Version: ^6.1
PHP Version: ^7.2.5
LDAP Type: OpenLDAP
my .env
LDAP_HOSTS=ldap.forumsys.com
LDAP_BASE_DN=dc=example,dc=com
LDAP_USERNAME=cn=read-only-admin,dc=example,dc=com
LDAP_PASSWORD=password
LDAP_PASSWORD_SYNC=true
my ldap.php
<?php
return [
'logging' => env('LDAP_LOGGING', false),
'connections' => [
'default' => [
'auto_connect' => env('LDAP_AUTO_CONNECT', true),
'connection' => Adldap\Connections\Ldap::class,
'settings' => [
'schema' => Adldap\Schemas\OpenLDAP::class,
'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
'hosts' => explode(' ', env('LDAP_HOSTS', 'corp-dc1.corp.acme.org corp-dc2.corp.acme.org')),
'port' => env('LDAP_PORT', 389),
'timeout' => env('LDAP_TIMEOUT', 5),
'base_dn' => env('LDAP_BASE_DN', 'dc=corp,dc=acme,dc=org'),
'username' => env('LDAP_USERNAME', 'username'),
'password' => env('LDAP_PASSWORD', 'secret'),
'follow_referrals' => false,
'use_ssl' => env('LDAP_USE_SSL', false),
'use_tls' => env('LDAP_USE_TLS', false),
],
],
],
];
my ldap_auth
<?php
return [
'connection' => env('LDAP_CONNECTION', 'default'),
'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,
'model' => App\User::class,
'rules' => [
// Denys deleted users from authenticating.
Adldap\Laravel\Validation\Rules\DenyTrashed::class,
// Allows only manually imported users to authenticate.
// Adldap\Laravel\Validation\Rules\OnlyImported::class,
],
'scopes' => [
// Only allows users with a user principal name to authenticate.
// Suitable when using ActiveDirectory.
// Adldap\Laravel\Scopes\UpnScope::class,
// Only allows users with a uid to authenticate.
// Suitable when using OpenLDAP.
// Adldap\Laravel\Scopes\UidScope::class,
],
'identifiers' => [
'ldap' => [
'locate_users_by' => 'uid',
'bind_users_by' => 'distinguishedname',
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'username', //'email',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
'passwords' => [
'sync' => env('LDAP_PASSWORD_SYNC', false),
'column' => 'password',
],
'login_fallback' => env('LDAP_LOGIN_FALLBACK', false),
'sync_attributes' => [
//'email' => 'userprincipalname',
'username' => 'uid',
'name' => 'cn',
],
'logging' => [
'enabled' => env('LDAP_LOGGING', true),
'events' => [
\Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
\Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
\Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
\Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
\Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
\Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
\Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
\Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
\Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
\Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
\Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
],
],
];
my loginController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = RouteServiceProvider::HOME;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function username()
{
return 'username';
}
}
Been through this pain myself.
It looks like you are connecting to LDAP with your service account, but I don't see where you are logging the authenticated user into Laravel. Do your users have to supply a username and password on a screen somewhere? If not, how do you grab the user and log them in to Laravel?
The way I did this in the businesses that had to go through LDAP was to have the normal Laravel login page, but a middle method within the login controller which sent a message to LDAP through the service account with the PW. If this succeeded, then login with Laravel's standard method. Basically just check the PW against LDAP and then log in rather than checking against the Laravel DB.
Example code - this will vary wildly but can give you an idea of what might work:
if(env('LOGIN', false) === 'LDAP'){
$ldap = new \App\Http\Controllers\ClientSpecific\BaseLDAPController();
$username = $request->input('username');
if($ldap->authenticate($username, $request->input('password'))){
return $this->sendLoginResponse($request);
}
}else {
if ($this->guard()->attempt($credentials, $request->has('remember'))) {
return $this->sendLoginResponse($request);
}
}
I know this is an old question, but I was still facing this issue even in 2020 and it took a lot of my time. Actually the problem is very silly if you are also trying to bind an OpenLDAP server with your Laravel application using Adldap2-Laravel package.
Adldap2-Laravel is by default configured for Microsoft's Active Directory. But for OpenLDAP, we need to properly change the Identifiers array as follows..
<?php
return [
// configurations settings...
'identifiers' => [
'ldap' => [
'locate_users_by' => 'uid', // changed from userprincipalname
'bind_users_by' => 'dn', // changed from distinguishedname
],
'database' => [
'guid_column' => 'objectguid',
'username_column' => 'username', //'email',
],
'windows' => [
'locate_users_by' => 'samaccountname',
'server_key' => 'AUTH_USER',
],
],
// rest of the configurations...
];
Do tell me if my answer is not clear for new comers since I'm also a newbie. I'll try to explain the solution further better :)

How to set file post properly PhpUnit

I'm trying to set a test to upload a file.
In the controller I need to check if everyting is ok (form validation).
The problem is the response gives me an error $request->dataFile->getClientOriginalExtension() , (vendor/symfony/http-foundation/File/UploadedFile.php)
Looks like the dataFile, or request or.... I dont know how to set it.
/**
#test
#group formPostFile
*/
public function formPostFile()
{
$test_file_path = base_path().'/httpdocs/test/Excel.xlsx';
$this->assertTrue(file_exists($test_file_path), $test_file_path.' Test file does not exist');
$_FILE = [
'filename' => [
'name' => $test_file_path,
'type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'size' => 10336,
'tmp_name' => $test_file_path,
'error' => 0
]
];
$data = [
'id' => '2',
'dataFile' => $_FILE
];
$response = $this->post('/excel', $data);
dd($response->getContent());
}
Utilise the Symfony/Illuminate class UploadedFile
$file = new UploadedFile(
$test_file_path,
$test_file_path,
filesize($test_file_path),
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
null,
true
);
LastParameter is testMode and should be true, i believe this will work out in your code, utilise it in a similar fashion as the array you already have like so.
$data = [
'id' => '2',
'dataFile' => $file
];

Installing user-management for Yii2.0

I've been trying to install user-management for Yii2.0, but getting ReflectionException while loading the page. I have attached the error page and directory structure below.
and the file path is as shown below.
I've searched a lot to find out the reason for this, but nothing worked out. can someone tell me what am I missing here to get it work. looks like the user-management installation documentation has some flaws. It is not clear enough to understand. Hope to get the steps to install. Thanks
Here is my console/web.php
<?php
$params = require(__DIR__ . '/params.php');
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'components' => [
'request' => [
// !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
'cookieValidationKey' => 'gAry7SfUr0oOjNQDqItsobmGBcJajQoW',
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
'user' => [
//'identityClass' => 'app\models\User',
'enableAutoLogin' => true,
'class' => 'app\webvimark\modules\user-management\components\UserConfig',
// Comment this if you don't want to record user logins
'on afterLogin' => function($event) {
\webvimark\modules\user-management\models\UserVisitLog::newVisitor($event->identity->id);
}
],
'errorHandler' => [
'errorAction' => 'site/error',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
// send all mails to a file by default. You have to set
// 'useFileTransport' to false and configure a transport
// for the mailer to send real emails.
'useFileTransport' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'db' => require(__DIR__ . '/db.php'),
],
'modules'=>[
'user-management' => [
'class' => 'webvimark\modules\user-management\UserManagementModule',
// 'enableRegistration' => true,
// Here you can set your handler to change layout for any controller or action
// Tip: you can use this event in any module
'on beforeAction'=>function(yii\base\ActionEvent $event) {
if ( $event->action->uniqueId == 'user-management/auth/login' )
{
$event->action->controller->layout = 'loginLayout.php';
};
},
],
],
'params' => $params,
];
if (YII_ENV_DEV) {
// configuration adjustments for 'dev' environment
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = [
'class' => 'yii\debug\Module',
];
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
return $config;
It seems to have a slight difference with the expected configuration for this extension.
Use this
'class' => 'webvimark\modules\UserManagement\components\UserConfig',
ie UserManagement instead of user-management is a configuration path and not a route

authorisation based on values not on verb

I'm implementing an authorisation process based on values not on verb.
Example:
all users/groups are allowed to update a db field
admin can set status to all possible values (confirmed | pending | cancelled)
supplier can set to 'confirmed'
All examples I find go around a user/group being able or not to insert,update or delete something.
Is there something out there to deal with situations like this out of the box, or this has be hard coded?
Basically what you need is something hard to maintain in any application: granular permissions.
You can get this to work easily using Cartalyst's Sentry. Here's how I do it:
All my routes are hierarchically organized and named as such:
<?php
Route::get('login', array('as'=>'logon.login', 'uses'=>'LogonController#login'));
Route::get('logged/out', array('as'=>'logon.loggedOut', 'uses'=>'LogonController#loggedOut'));
Route::group(array('before' => 'auth'), function()
{
Route::get('logout', array('as'=>'logon.logout', 'uses'=>'LogonController#logout'));
Route::group(array('before' => 'permissions'), function()
{
Route::get('store/checkout/shipping/address', array('as'=>'store.checkout.shipping.address', 'uses'=>'StoreController#shippingAddress'));
Route::get('store/checkout/payment/confirmed', array('as'=>'store.checkout.payment.confirmed', 'uses'=>'StoreController#confirmed'));
Route::get('profile', array('as'=>'profile.show', 'uses'=>'ProfileController#show'));
});
});
Those under the filter 'permissions' are subject to check if user has rights to use them:
Route::filter('permissions', function()
{
$name = Route::current()->getName();
$name = 'system' . ( ! empty($name) ? '.' : '') . $name;
if (!Permission::has($name)) {
App::abort(401, 'You are not authorized to access route '.$name);
}
});
Basically here I get the current route name, add 'system.' to it and check if the user has this particular permission.
Here's how I create my groups and populate permissions:
<?php
public function seedPermissions()
{
DB::table('groups')->truncate();
$id = 1;
Sentry::getGroupProvider()->create(array(
'id' => $id++,
'name' => 'Super Administrators',
'permissions' => array(
'system' => 1,
),
));
Sentry::getGroupProvider()->create(array(
'id' => $id++,
'name' => 'Administrators',
'permissions' => array(
'system.users' => 1,
'system.products' => 1,
'system.store' => 1,
'system.profile' => 1,
),
));
Sentry::getGroupProvider()->create(array(
'id' => $id++,
'name' => 'Managers',
'permissions' => array(
'system.products' => 1,
'system.store' => 1,
'system.profile' => 1,
),
));
Sentry::getGroupProvider()->create(array(
'id' => $id++,
'name' => 'Users',
'permissions' => array(
'system.store.checkout' => 1,
'system.profile' => 1,
),
));
}
So if a user is trying to add some shipping address, the route 'store.checkout.payment.confirmed', as every user has access to 'system.store.checkout', everything inside that route will available to him.
And this is how I check for permissions:
public static function has($permission)
{
$all = [];
$parts = explode('.',$permission);
$permission = '';
foreach($parts as $part) {
$permission .= (!empty($permission) ? '.' : '') . $part;
$all[] = $permission;
}
return Sentry::check() and Sentry::getUser()->hasAnyAccess($all);
}
It basically builds a list of routes:
system
system.store
system.store.checkout
system.store.checkout.payment
system.store.checkout.payment.confirmed
And if Sentry finds one of those in the users granular permissions it will return true.
Now I just have to add users to groups:
Sentry::findUserById(1)->addGroup( Sentry::getGroupProvider()->findByName('Users') );
And if I need to go granular on a particular user/permission I just need to:
$user = Sentry::findUserById(1);
$user->permissions['store.checkout.payment'] = false;
$user->save();
And the user will never be able to pay for anything in the store again. :)

Resources