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

 

Laravel 5: Security – Authentication

Laravel 5: Security – Authentication


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

Laravel built in single level authentication

Single level means, that you have just one kind of authenticated user.
You can then assign different roles using authorization.
This will not work for multi level authorization, e.g. when you need to have structure like for instance:

  • students
  • teachers
  • associates

where each group should have it’s separate admin and database table.
For that, see this link.

But if single level is enough for you, this is how to get it working:

Some definitions
guards

Guards define how users are authenticated for each request.
Guards are about where your application stores an authenticated user’s details (i.e. session, database, etc).
In other words, what driver is used (session, or token) and what provider (which model and what database driver)
seeconfig\auth.php

providers

Providers define how users are retrieved from your persistent storage.
Providers are how your application authenticates user, i.e. Eloquent, an API, and so on.
Which driver (eloquent, database) and which model (e.g. App\User).
seeapp\Providers\AuthServiceProvider.php

Redirect after authentication

This code goes into your LoginController (or any other doing just that).

via property

via method

Login throttling

Throttling is a way to control how many times user can attempt to login before system will apply cool-down period.
Cool-down period is a forced break period, before user is allowed to try to login again.
Cool-down period length can also be set.

Since Laravel 5.3, it is hardcoded.
In previous versions of Laravel 5 it was possible to use maxLoginAttempts and lockoutTime inside of Login controller to define login attempts and lock out time (cool-down).

You can change it by hand in this trait

Just look for this method and make changes – read comments in code below to see what to change:

… or you can bring back maxLoginAttempts and lockoutTime

Detailed, step-by-step procedure is described here.

Default user identifier

When user is being identified, Laravel searches by default for user email in user table ’email’ column (field).
Then, it compares passwords.

If you use other column to find user, e.g. ‘username’ then you have to tell Laravel about it.

This is how (in LoginController):

Get currently authenticated user
via Auth facade

via Request instance

Once a user is authenticated, you may access the authenticated user via an Illuminate\Http\Request instance.

Protecting resources – authenticated users only
via Auth facade
This allows spot protection anywhere in code.
Quite handy in some cases.
In real life access protection is easier done by protecting routes, or controllers.
See below.

via controller __construct() method
This allows protecting all controller used resources.

via protecting route itself

Similar to controller __counstruct() protection (see above), just applied to route leading to controller.

Manually authenticating users
basic approach

extra authentication constraints

use custom guard

remember users
Note:
users table must include the string remember_token column.

NOTE:
Must remember this!!!
https://github.com/laravel/framework/issues/16311
In short, use it, or clear old sessions, when e.g. changing password.
Also read about: AuthenticateSession here.
Logging user out

Programmatically login user
by Instance
Requires Illuminate\Contracts\Auth\Authenticatable in model.

by ID

authenticate A User Once (no cookies), good for stateless API

Login / logout built in events

Laravel raises a variety of events during the authentication process.
You may attach listeners to these events in your EventServiceProvider.

Read also about:

 

Laravel 5: Security – Authentication: lets bring back maxLoginAttempts and lockoutTime

Laravel 5: Security – maxLoginAttempts and lockoutTime


Lets bring back maxLoginAttempts and lockoutTime phased out by ThrottlesLogins trait.

As of Laravel 5.3 maxLoginAttempts and lockoutTime are not available anymore
Earlier we had capacity to easily set maximum login attempts and lockout time.
But creators on Laravel decided to remove that, when they introduced ThrottlesLogins trait.
They just hardcoded these, arbitrarily setting them to 5 unsuccessful trials and one minute delay.
Sometimes you may need more and may want to do that in an easy way.

Here is one of approaches – you just need to tweak trait ThrottlesLogins and you are good to go.

Some explanation first.

When you use Laravel built in authentication scaffolding, setup, brought you by this command:

… inside of your LoginController, you will see trait AuthenticatesUsers pulled in.
When you look inside of mentioned trait, you will see another trait ThrottlesLogins pulled in.
This is the one we need to tweak.

step 1

Find our ThrottlesLogins trait:

… and change protected function hasTooManyLoginAttempts to:

step 2

Above our changed protected function hasTooManyLoginAttempts, add two extra methods:

step 3

Now you can set how many attempt and how long cool-down period you need (in minutes) directly in LoginController pulling in trait AuthenticatesUsers or anywhere, where you directly pull trait ThrottlesLogins.

login attempts:

login cool-down:

Tested and works in Laravel 5.3 and Laravel 5.4.

Laravel 5.2 offers maxLoginAttempts and lockoutTime out of the box.

I have no idea how it plays with Laravel 5.1 or 5.0, as I have not tested it.

That’s about the size of it.