Add authorization to your spatie/laravel-data
objects
This package adds authorization to your spatie/laravel-data
objects, which
is very useful if you want to expose data objects to the frontend (e.g. when using Inertia), but still need to check
if the user is allowed to perform certain actions.
Install the package via composer:
composer require ephort/laravel-data-authorization
This package is intended to be used with Inertia, but does not require it or depend on it.
To add the authorization checks to your data objects, extend the DataWithAuthorization
class.
All the methods of the base Data
class are still available.
Next, implement the static getAuthorizations
method, which should return an array containing the
names of the actions that need to be exposed and checked.
use Ephort\LaravelDataAuthorization\DataWithAuthorization;
class UserData extends DataWithAuthorization
{
public function __construct(
public int $id,
public string $name,
) {
}
public static function getAuthorizations(): array
{
return [
'view',
'update',
'delete',
];
}
}
When the data object is transformed, a lazy authorization
property is appended to the resulting array.
This property contains a key for each defined policy action and is evaluated by Gate::allows
.
{
"id": 1,
"name": "Taylor Otwell",
"authorization": {
"view": true,
"update": false,
"delete": false
}
}
Because the authorization
property is lazy, we can exclude it from the data object to avoid calling the gate on every
serialization.
UserData::from($user)->exclude('authorization');
Or use the built-in helper method:
UserData::from($user)->withoutAuthorization();
When using
a custom from
method,
the pipeline that resolves authorizations is not used.
This means you must call the static resolveAuthorizationArray
method manually when instantiating your
data object:
public static function fromModel(User $user): self
{
return self::from([
'id' => $user->id,
'name' => $user->name,
'authorization' => static::resolveAuthorizationArray($user),
]);
}
You can also wrap the authorization
array in a Lazy property if needed:
Lazy::create(fn () => static::resolveAuthorizationArray($user))->defaultIncluded();
Thanks to Spatie, it's very easy to generate TypeScript interfaces from data objects and enums.
Install the TypeScript Transformer package and publish its
configuration file:
composer require spatie/laravel-typescript-transformer
php artisan vendor:publish --tag=typescript-transformer-config
Open config/typescript-transformer.php
and add the following collector and transformer:
Ephort\LaravelDataAuthorization\Collectors\DataAuthorizationTypeScriptCollector::class
must be the first collector.
'collectors' => [
+ Ephort\LaravelDataAuthorization\Collectors\DataAuthorizationTypeScriptCollector::class,
Spatie\TypeScriptTransformer\Collectors\DefaultCollector::class,
Spatie\TypeScriptTransformer\Collectors\EnumCollector::class,
],
'transformers' => [
Spatie\LaravelTypeScriptTransformer\Transformers\SpatieStateTransformer::class,
Spatie\TypeScriptTransformer\Transformers\EnumTransformer::class,
Spatie\TypeScriptTransformer\Transformers\SpatieEnumTransformer::class,
Spatie\LaravelTypeScriptTransformer\Transformers\DtoTransformer::class,
+ Ephort\LaravelDataAuthorization\Transformers\DataAuthorizationTypeScriptTransformer::class,
],
The above configuration uses a collector provided by this package, which finds data objects that
extend DataWithAuthorization
and generates typings with their authorizations. This is what powers typed authorization
support.
composer test
Please see CHANGELOG for more information on what has changed recently.
The code is primarily copied from the awesome project Hybridly by Enzo Innocenzi, which is a great alternative to Inertia.
The MIT License (MIT). Please see License File for more information.