Laravel 5: Security – Authorization

Laravel 5: Security – Authorization


Authentication vs Authorization
Authentication: login + password (who you are)
Authorization: permissions (what you are allowed to do)

Gates and Policies

There are two primary ways of authorizing actions:

  • gates (for simpler stuff)
  • policies (for more complex)
gates

Gates provide a simple, Closure based approach to authorization.
Gates are most applicable to actions which are not related to any model or resource, such as viewing an administrator dashboard.

policies

Policies group their logic around a particular model or resource.
Policies should be used when you wish to authorize an action for a particular model or resource.

Gates
writing Gate

Gates are closures.
Closure above returns bool.

They are defined in boot() method, in:

Put them below $this->registerPolicies()

We use the Gate facade, so do not forget to call it on top.

This is how it looks like:

  1. First argument in closure is User instance
  2. Second can be relevant object to what you do, e.g. Post instance

You may type hint it in boot().

authorizing actions using Gate
authenticated user

To authorize action, you call closure in code, where you need authorization – e.g. in controller – using methods:

  • allows
  • denies

Here are closure examples.

First argument – ‘update-post’ is a name of your gate.
It should ne unique, since all your gates will be stored in boot() method of AuthServiceProvider.

No need to bother with $user object, Laravel auto-loads it for you.
If your gate used another object, load it as a second argument.
You may want to type hint it into method using gate closure.

particular user, selected by you

This could be an authenticated user, or any other selected by you user.
You have to deliver user object by yourself here.

For particular user use forUser() method:

Policies
step 1: generating Policy

Policies are classes that organize authorization logic around a particular model or resource.

For instance, Post model may have PostPolicy class with all you need to authorize post updates, posting, deletion.
Naming is arbitrary. It is up to you.

Policies are stored in catalog:

Policy scaffolding can be done using Artisan command:

Policy CRUD scaffolding can be also auto-generated via Artisan:

CRUD way will create 4 methods inside of PostPolicy boilerplate:

  • view
  • create
  • update
  • delete

It will also type hint your model given in Artisan command into arguments.
Just a handy shortcut.

It will NOT:

  • write anything to given model
  • create given model, if does not exists
step 2: registering policy

Policy needs to be registered with Laravel via AuthServiceProvider.

You can find it in folder:

You have to pull (use) Post and PostPolicy – and any other Model with policy you are registering.

Then you use property $policies, like so:

… to map given model to given policy.

step 3: authorize actions via policy
policy methods

PostPolicy methods can be named anything you like.
You do not have to follow same naming as in Post model.

You can name same as in Post model, like:

… but you can also name it anything like:

Note:
Just search on page for ‘rumpelstiltskin‘, to see why Laravel does not force you to conform to any naming convention here.

As you see above, we return boolean value, by comparing:

  • authenticated user id and
  • post creator id

If they are same, method returns true and user can update post, as any post creator should have ability to do.

Of course, you may have some policy, that prevent post updating after 30 minutes from creation, then you could run appropriate code against time also.

methods without model

If you create post, you may not have Post instance yet, so you only type hint User only and just check, if he is authenticated.

Additionally you may also check, if user role allows for action, or anything you desire.

policy filters

If you want to do something before policy method is called at all, like authorizing Admin, you can use ‘before’ method.

Of course you can do that in policy method itself, but if you have more methods, then you’d be just repeating same code in each method.

Ability is used to fine-tune stuff inside of before() method.

Important – if you have before() method, you can:

  • return true: Admin is authorized and buck stops here – policy method is NOT called anymore – no need
  • return false: no one is authorized – policy method is NOT called anymore – no need
  • return nothing ‘null’: action continues – Laravel calls appropriate policy
step 4: authorizing actions using policies
via User model

You use two self-explanatory methods:

  • can
  • cant
all but insert

Wherever you need to authorize anything, you just use this construct:

How it works

If you did everything right in steps before, then methods can/cant will:

  1. check if policy is registered, if it is they will use it
  2. if not policy is registered, they will look for closure based Gate
  3. if you forgot to do something right, you will get an exception
insert action

Since you have no current instance of model $post, as you are just creating it, you cannot pass it here, so you use this construct (Post::class):

via middleware
all but insert

We have implicit binding here (type-hinted Post model as closure argument), so our good ole’ Laravel is going to do some lifting for us.

As you can see above, route carries variable {post}.
That variable is used to get instance of Post model using that variable.
Then, that instance is being passed to policy as an argument.

Note:
If Closure has not been type hinted model, then policy would get {post} argument itself.

Lets take a look at that middleware:

  • can: this one of authorizing methods (the other is cant)
  • update: is policy method, which is registered for Post model in AuthServiceProvider
    note: if you named your policy rumpelstiltskin instead of update, call it here:
    middleware(‘can:rumpelstiltskin,post’);
  • post: this is a name of our model Post

Note: just watch these colons and commas and remember what divides what.

insert action

As before, we cannot pass model instance, as we do not have it yet. We are just creating it/new.
So, we are creating this construct:

via controller helper

Laravel provides a helpful ‘authorize‘ method to any of your controllers which extend the App\Http\Controllers\Controller base class.

And this is how you use it.

all but insert

How ‘authorize‘ works:

  1. You specify policy method ‘update‘.
  2. You specify $post model, so Laravel can find policy class via registration in AuthServiceProvider.
  3. If authorization fails, the authorize method will throw an Illuminate\Auth\Access\AuthorizationException, which the default Laravel exception handler will convert to an HTTP response with a 403 status code and thus code will not proceed to update action.
insert action

This is ‘create‘ method construct:

via blade templates

When writing Blade templates, you may wish to display a portion of the page only if the user is authorized to perform a given action.
You may use the @can and @cannot family of directives.

all but insert

This is how it looks using @can and @cannot shortcut method.

This is how it looks like when you do not use: @can and @cannot:

 

insert action