1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Cortex\Foundation\Http\Controllers; |
6
|
|
|
|
7
|
|
|
use ReflectionClass; |
8
|
|
|
use ReflectionMethod; |
9
|
|
|
use Illuminate\Support\Str; |
10
|
|
|
use Illuminate\Foundation\Auth\Access\AuthorizesRequests; |
11
|
|
|
|
12
|
|
|
class AuthorizedController extends AuthenticatedController |
13
|
|
|
{ |
14
|
|
|
use AuthorizesRequests; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* The resource Ability Map. |
18
|
|
|
* |
19
|
|
|
* @var array |
20
|
|
|
*/ |
21
|
|
|
protected $resourceAbilityMap = [ |
22
|
|
|
'activities' => 'audit', |
23
|
|
|
'index' => 'list', |
24
|
|
|
'logs' => 'audit', |
25
|
|
|
]; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* The resource methods without models. |
29
|
|
|
* |
30
|
|
|
* @var array |
31
|
|
|
*/ |
32
|
|
|
protected $resourceMethodsWithoutModels = []; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Resource action whitelist. |
36
|
|
|
* Array of resource actions to skip mapping to abilities automatically. |
37
|
|
|
* |
38
|
|
|
* @var array |
39
|
|
|
*/ |
40
|
|
|
protected $resourceActionWhitelist = []; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Create a new authorized controller instance. |
44
|
|
|
* |
45
|
|
|
* @throws \Illuminate\Auth\Access\AuthorizationException |
46
|
|
|
*/ |
47
|
|
|
public function __construct() |
48
|
|
|
{ |
49
|
|
|
parent::__construct(); |
50
|
|
|
|
51
|
|
|
if (property_exists(static::class, 'resource')) { |
52
|
|
|
$this->authorizeResource($this->resource); |
|
|
|
|
53
|
|
|
} else { |
54
|
|
|
// At this stage, sessions still not loaded yet, and `AuthorizationException` |
55
|
|
|
// depends on seesions to flash redirection error msg, so delegate to a middleware |
56
|
|
|
// Since Laravel 5.3 controller constructors executed before middleware to be able to append |
57
|
|
|
// new middleware to the pipeline then all middleware executed together, and sessions started in `StartSession` middleware |
|
|
|
|
58
|
|
|
$this->middleware('can:null'); |
59
|
|
|
} |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* {@inheritdoc} |
64
|
|
|
*/ |
65
|
|
|
public function authorizeResource($model, $parameter = null, array $options = [], $request = null): void |
66
|
|
|
{ |
67
|
|
|
$middleware = []; |
68
|
|
|
$parameter = $parameter ?: Str::snake(class_basename($model)); |
69
|
|
|
|
70
|
|
|
foreach ($this->mapResourceAbilities() as $method => $ability) { |
71
|
|
|
$modelName = in_array($method, $this->resourceMethodsWithoutModels()) ? $model : $parameter; |
72
|
|
|
|
73
|
|
|
$middleware["can:{$ability},{$modelName}"][] = $method; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
foreach ($middleware as $middlewareName => $methods) { |
77
|
|
|
$this->middleware($middlewareName, $options)->only($methods); |
78
|
|
|
} |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Map resource actions to resource abilities. |
83
|
|
|
* |
84
|
|
|
* @return array |
85
|
|
|
*/ |
86
|
|
|
protected function mapResourceAbilities(): array |
87
|
|
|
{ |
88
|
|
|
// Reflect calling controller |
89
|
|
|
$controller = new ReflectionClass(static::class); |
90
|
|
|
|
91
|
|
|
// Get public methods and filter magic methods |
92
|
|
|
$methods = array_filter($controller->getMethods(ReflectionMethod::IS_PUBLIC), function ($item) use ($controller) { |
|
|
|
|
93
|
|
|
return $item->class === $controller->name && mb_substr($item->name, 0, 2) !== '__' && ! in_array($item->name, $this->resourceActionWhitelist); |
|
|
|
|
94
|
|
|
}); |
95
|
|
|
|
96
|
|
|
// Get controller actions |
97
|
|
|
$actions = array_combine($items = array_map(function ($action) { |
98
|
|
|
return $action->name; |
99
|
|
|
}, $methods), $items); |
100
|
|
|
|
101
|
|
|
// Map resource actions to resourse abilities |
102
|
|
|
array_walk($actions, function ($value, $key) use (&$actions) { |
103
|
|
|
$actions[$key] = array_get($this->resourceAbilityMap(), $key, $value); |
104
|
|
|
}); |
105
|
|
|
|
106
|
|
|
return $actions; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* {@inheritdoc} |
111
|
|
|
*/ |
112
|
|
|
protected function resourceAbilityMap(): array |
113
|
|
|
{ |
114
|
|
|
return array_merge(parent::resourceAbilityMap(), $this->resourceAbilityMap); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* {@inheritdoc} |
119
|
|
|
*/ |
120
|
|
|
protected function resourceMethodsWithoutModels() |
121
|
|
|
{ |
122
|
|
|
return array_merge(parent::resourceMethodsWithoutModels(), $this->resourceMethodsWithoutModels); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.