feat: Permission System Hướng B - Models, Command, User can(), session cache
This commit is contained in:
@@ -29,9 +29,83 @@ class User extends Authenticatable implements FilamentUser
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
'extra_permissions' => 'array',
|
||||
'excluded_permissions' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
public function roleTemplate()
|
||||
{
|
||||
return $this->belongsTo(RoleTemplate::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tính toán effective permissions từ role template + extra - excluded.
|
||||
* Cache trong session (1 lần/login).
|
||||
*/
|
||||
public function getEffectivePermissions(): array
|
||||
{
|
||||
$cacheKey = "user.{$this->id}.permissions";
|
||||
|
||||
if (session()->has($cacheKey)) {
|
||||
return session()->get($cacheKey);
|
||||
}
|
||||
|
||||
$permissions = $this->calculateEffectivePermissions();
|
||||
session()->put($cacheKey, $permissions);
|
||||
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
public function hasEffectivePermission(string $permission): bool
|
||||
{
|
||||
return in_array($permission, $this->getEffectivePermissions());
|
||||
}
|
||||
|
||||
public function clearPermissionCache(): void
|
||||
{
|
||||
session()->forget("user.{$this->id}.permissions");
|
||||
}
|
||||
|
||||
protected function calculateEffectivePermissions(): array
|
||||
{
|
||||
$templatePerms = [];
|
||||
|
||||
if ($this->roleTemplate) {
|
||||
$templatePerms = $this->roleTemplate->permissions ?? [];
|
||||
}
|
||||
|
||||
// Flatten template permissions từ {"contracts":["view","create"]} thành ["contracts.view","contracts.create"]
|
||||
$templateFlat = [];
|
||||
foreach ($templatePerms as $module => $actions) {
|
||||
foreach ($actions as $action) {
|
||||
$templateFlat[] = "{$module}.{$action}";
|
||||
}
|
||||
}
|
||||
|
||||
$extra = $this->extra_permissions ?? [];
|
||||
$excluded = $this->excluded_permissions ?? [];
|
||||
|
||||
return array_values(array_diff(
|
||||
array_unique(array_merge($templateFlat, $extra)),
|
||||
$excluded
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override can() để tích hợp với Laravel Authorization.
|
||||
* Nếu ability là dạng "contracts.view" → dùng effective permissions.
|
||||
* Ngược lại fallback về parent.
|
||||
*/
|
||||
public function can($abilities, $arguments = []): bool
|
||||
{
|
||||
if (is_string($abilities) && str_contains($abilities, '.')) {
|
||||
return $this->hasEffectivePermission($abilities);
|
||||
}
|
||||
|
||||
return parent::can($abilities, $arguments);
|
||||
}
|
||||
|
||||
public function canAccessPanel(Panel $panel): bool
|
||||
{
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user