https://github.com/conedevelopment/policy
Using Laravel's authorization on the front-end.
https://github.com/conedevelopment/policy
Last synced: 2 months ago
JSON representation
Using Laravel's authorization on the front-end.
- Host: GitHub
- URL: https://github.com/conedevelopment/policy
- Owner: conedevelopment
- License: mit
- Archived: true
- Created: 2019-06-04T11:45:11.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2021-03-02T07:21:08.000Z (about 5 years ago)
- Last Synced: 2025-11-22T05:20:24.706Z (4 months ago)
- Language: PHP
- Homepage: https://pineco.de/implementing-laravels-authorization-front-end/
- Size: 51.8 KB
- Stars: 97
- Watchers: 6
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Policy
Using Laravel's authorization on the front-end.
A nice tool for SPAs and front-end heavy applications.
If you want to see behind the package, we suggest to read this post:
[Implementing Laravel’s Authorization on the Front-End](https://pineco.de/implementing-laravels-authorization-front-end/).
### Table of contents
1. [Getting Started](#getting-started)
2. [Publishing and setting up the JavaScript library](#publishing-and-setting-up-the-javascript-library)
- [Setting up the Gate.js](#setting-up-the-gatejs)
- [Initializing a gate instance](#initializing-a-gate-instance)
- [Passing the user to the gate instance](#passing-the-user-to-the-gate-instance)
- [Using it as a Vue service](#using-it-as-a-vue-service)
- [The @currentUser blade directive](#the-currentuser-blade-directive)
3. [Using the policies and the Gate.js](#using-the-policies-and-the-gatejs)
- [The available methods](#the-available-methods)
- [Adding the UsesModelName trait to the models](#adding-the-usesmodelname-trait-to-the-models)
- [Generating policies with artisan](#generating-policies-with-artisan)
- [Writing the policy rules](#writing-the-policy-rules)
4. [Example](#example)
5. [Contribute](#contribute)
## Getting started
You can install the package with composer, running the `composer require thepinecode/policy` command.
Since the package supports auto-discovery, Laravel will register the service provider automatically behind the scenes.
In some cases you may disable auto-discovery for this package.
You can add the provider class to the `dont-discover` array to disable it.
Then you need to register it manually again.
## Publishing and setting up the JavaScript library
By default the package provides a `Gate.js` file, that will handle the policies.
Use the `php artisan vendor:publish` command and choose the `Pine\Policy\PolicyServiceProvider` provider.
After publishing you can find your fresh copy in the `resources/js/policies` folder if you are using Laravel 5.7+.
If your application is lower than 5.7, the JS will be published in the `resources/assets/js/policies`.
### Setting up the Gate.js
Then you can import the `Gate` class and assign it to the `window` object.
```js
import Gate from './policies/Gate';
window.Gate = Gate;
```
### Initializing a gate instance
From this point you can initialize the translation service anywhere from your application.
```js
let gate = new Gate;
```
### Passing the user to the gate instance
The `Gate` object requires a passed user to work properly. This can be a `string` or an `object`.
By default, it looks for the `window['user']` object, however you may customize the key or the object itself.
```js
let gate = new Gate; // window['user']
let gate = new Gate('admin'); // window['admin']
let gate = new Gate({ ... }); // uses the custom object
```
> Note, you can pass any object as a *user*.
> If you pass a team or a group object, it works as well. Since you define the logic behind the `Gate`,
> you can pass anything you wish.
### Using it as a Vue service
If you want to use it from Vue templates directly you can extend Vue with this easily.
```js
Vue.prototype.$Gate = new Gate;
```
```html
...
```
```js
computed: {
hasPermission: {
return this.$Gate.allow('view', this.model);
}
}
```
### The @currentUser blade directive
To make it quicker, the package comes with a `@currentUser` blade directive.
This does nothing more, but to print the currently authenticated user as `JSON` and assign it to the `window` object.
```html
@currentUser
window['user'] = { ... };
```
You may override the default key for the user. You can do that by passing a string to the blade directive.
```html
@currentUser ('admin')
window['admin'] = { ... };
```
> If there is no authenticated user, the value will be `null`.
## Using the policies and the Gate.js
### The available methods
#### allow()
The `allow()` accepts two parameters. The first is the action to perform, the second is the **model object** or the **model name**, like in Laravel.
> Note: **model name** should be a lower case version of the actual model name in Laravel: for example `Comment` becomes `comment`.
```js
gate.allow('view', model);
gate.allow('create', 'comment');
```
#### deny()
The `deny()` has the same signature like `allow()` but it will negate its return value.
```js
gate.deny('view', model);
gate.deny('create', 'comment');
```
#### before()
Like in Laravel, in the `before()` method you can provide a custom logic to check for special conditions.
If the condition passes, the rest of the policy rules in the `allow()` or `deny()` won't run at all.
However if the condition fails, the policy rules will get place.
To use the `before()` method, you may extend the gate object and define your custom logic.
```js
Gate.prototype.before = function () {
return this.user.is_admin;
}
```
> Please note, to use the `this` object correctly,
> **use the traditional function signature instead of the arrow (() => {}) functions**.
### Adding the `UsesModelName` trait to the models
Since, the policies use real JSON shaped eloquent models, the models have to use the `Pine\Policy\UsesModelName`
trait that generates the proper model name. This model name attribute is used for pairing the proper policy with
the model by the `Gate.js`.
```php
use Pine\Policy\UsesModelName;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
use UsesModelName;
protected $appends = ['model_name'];
}
```
> Please note, to be able to use this attribute on the front-end, the attribute has to be appended to the JSON form.
> You can read more about appending values to JSON in the
> [docs](https://laravel.com/docs/master/eloquent-serialization#appending-values-to-json).
### Generating policies with artisan
The package comes with an artisan command by default, that helps you to generate your JavaScript policies easily.
To make a policy, run the `php artisan make:js-policy Model` command, where the `Model` is the model's name.
```sh
php artisan make:js-policy Comment
```
This command will create the `CommentPolicy.js` file next to the `Gate.js` in the `resources/js/policies` directory.
If you are using lower than Laravel 5.7, the policies will be generated in the `resources/assets/js/policies` directory.
> Note, the command will append the `Policy` automatically in the file name.
> It means you may pass only the model name when running the command.
After you generated the policy files, use `npm` to compile all the JavaScript, including policies.
***
#### Important!
**The policies are registered automatically**. It means, no need for importing them manually.
The gate instance will **automatically** populate the policies.
Every policy will be used where it matches with the model's `model_name` attribute.
Based on
[Laravel's default app.js](https://github.com/laravel/laravel/blob/master/resources/js/app.js#L19-L20)
the Gate instance
[registers the policies automatically](https://github.com/thepinecode/policy/blob/master/resources/js/Gate.js#L14-L18)
when calling `npm run dev`, `npm run prod` and so on.
***
### Writing the policy rules
Policies – like in Laravel – have the following methods by default:
`viewAny`, `view`, `create`, `update`, `restore`, `delete` and `forceDelete`.
Of course, you can use custom methods as well, policies are fully customizables.
```js
...
view(user, model)
{
return user.id == model.user_id;
}
create(user)
{
return user.is_admin;
}
approve(user, model)
{
return user.is_editor && user.id == model.user_id;
}
...
```
## Example
```js
// app.js
Vue.prototype.$Gate = new Gate;
Vue.component('posts', {
mounted() {
axios.get('/api/posts')
.then(response => this.posts = response.data);
},
data() {
return {
posts: [],
};
},
template: `
Create post
`
});
let app = new Vue({
//
})
```
```html
@currentUser
```
## Contribute
If you found a bug or you have an idea connecting the package, feel free to open an issue.