Skip to content

Instantly share code, notes, and snippets.

@mdmunir
Created March 4, 2022 11:27
Show Gist options
  • Save mdmunir/d264a64fafef63d771c295d897a7fa10 to your computer and use it in GitHub Desktop.
Save mdmunir/d264a64fafef63d771c295d897a7fa10 to your computer and use it in GitHub Desktop.
Laravel access control
<?php
namespace App\Http\Middleware;
use App\Models\Auth;
use Closure;
use Illuminate\Http\Request;
use yii\db\Query;
use function abort;
use function auth;
use function config;
use function env;
/**
* Description of AccessControl
*
* @author Misbahul D Munir <[email protected]>
* @since 1.0
*/
class AccessControl
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (!env('ACCESS_CONTROL_ENABLE', false)) {
return $next($request);
}
$allowed = config('auth.allowed_route', []);
$route = $request->route();
if ($route && ($name = $route->getName())) {
if (in_array($name, $allowed)) {
return $next($request);
} elseif ($user = auth()->user()) {
/* @var $user Auth */
$roles = \yii\helpers\ArrayHelper::getColumn($user->roles, 'role_id');
$query = (new Query())
->from('role_action ra')
->where([
'ra.role_id' => $roles,
'ra.action' => $name
]);
if ($query->exists()) {
return $next($request);
}
abort(403, 'Forbiden');
}
abort(401, 'Unauthorized');
}
return $next($request);
}
}
<?php
namespace App\Models;
use App\Classes\ActiveRecord;
use App\Models\RoleAction;
use App\Models\RoleMenu;
use Dee;
use Illuminate\Support\Facades\Route;
use yii\behaviors\BlameableBehavior;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveQuery;
use yii\helpers\Inflector;
use function auth;
/**
* This is the model class for table "roles".
*
* @property int $id
* @property string $name
* @property string|null $description
* @property int $level
* @property bool $active
* @property int|null $created_by
* @property int|null $updated_by
* @property string|null $created_at
* @property string|null $updated_at
*
* @property RoleAction[] $roleActions
* @property array $actions
*/
class Role extends ActiveRecord
{
/**
* {@inheritdoc}
*/
public static function tableName()
{
return 'role';
}
/**
* {@inheritdoc}
*/
public function rules()
{
return [
[['name'], 'required'],
[['level',], 'integer'],
[['active'], 'boolean'],
[['name', 'description'], 'string', 'max' => 255],
];
}
/**
* {@inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'name' => 'Name',
'description' => 'Description',
'level' => 'Level',
'created_by' => 'Created By',
'updated_by' => 'Updated By',
'created_at' => 'Created At',
'updated_at' => 'Updated At',
];
}
public function getActions()
{
$actions = $this->getSystemRoutes();
foreach ($this->roleActions as $row) {
$actions[$row->action] = true;
}
$result = [];
foreach ($actions as $name => $value) {
list($group, $action) = explode('.', $name, 2);
if(!isset($result[$group])){
$result[$group] = [
'name' => $group,
'label' => Inflector::titleize($group),
'actions' => []
];
}
$result[$group]['actions'][] = [
'name' => $name,
'label' => Inflector::titleize($action),
'assigned' => $value
];
}
return array_values($result);
}
public function getMenus()
{
$assigned = RoleMenu::find()
->where(['role_id' => $this->id])
->asArray()
->indexBy(['menu_id'])
->all();
return Menu::resolve($assigned);
}
public function assignAction(array $actions)
{
return Dee::db()->transaction(function()use($actions) {
$roleId = $this->id;
$userId = auth()->id();
$now = Dee::now();
$deleted = RoleAction::deleteAll(['role_id' => $this->id]);
$values = [];
foreach ($actions as $row) {
if (!empty($row['assigned'])) {
$values[] = [$roleId, $row['name'], $now, $now, $userId, $userId];
}
}
$insert = 0;
if (count($values)) {
$command = Dee::db()->createCommand();
$columns = ['role_id', 'action', 'created_at', 'updated_at', 'created_by', 'updated_by'];
$insert = $command->batchInsert(RoleAction::tableName(), $columns, $values)->execute();
}
return [
'deleted' => $deleted,
'insert' => $insert,
];
});
}
public function assignMenu(array $menus)
{
return Dee::db()->transaction(function()use($menus) {
$roleId = $this->id;
$userId = auth()->id();
$now = Dee::now();
$deleted = RoleMenu::deleteAll(['role_id' => $this->id]);
$values = [];
foreach ($menus as $row) {
if (!empty($row['assigned'])) {
$values[] = [$roleId, $row['id'], $now, $now, $userId, $userId];
}
}
$insert = 0;
if (count($values)) {
$command = Dee::db()->createCommand();
$columns = ['role_id', 'menu_id', 'created_at', 'updated_at', 'created_by', 'updated_by'];
$insert = $command->batchInsert(RoleMenu::tableName(), $columns, $values)->execute();
}
return[
'deleted' => $deleted,
'insert' => $insert,
];
});
}
/**
* Gets query for [[RoleAction]].
*
* @return ActiveQuery
*/
public function getRoleActions()
{
return $this->hasMany(RoleAction::class, ['role_id' => 'id']);
}
public function behaviors(): array
{
return[
TimestampBehavior::class,
BlameableBehavior::class,
];
}
public function extraFields()
{
return[
'roleActions',
'actions',
'menus',
];
}
private static $_routes;
/**
*
* @return array
*/
public function getSystemRoutes()
{
if (self::$_routes === null) {
// list routes
foreach (Route::getRoutes()->getRoutes() as $route) {
$name = $route->getName();
if ($name && strncmp($name, 'ignition.', 9) != 0 && strpos($name, '.') > 0) {
self::$_routes[$name] = false;
}
}
ksort(self::$_routes);
}
return self::$_routes;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment