2016年11月26日 星期六

The auth scaffold in Laravel 5.2

If you're like me, many of the applications you build in Laravel have a similar Saas-type framework: user signup, user login, password reset, public sales page, logged-in dashboard, logout route, and a base Bootstrap style for when you're just getting started.
Laravel used to have a scaffold for this out of the box. It disappeared recently, to my great chagrin, but it's now back as an Artisan command: make:auth.
Command line output of artisan make:auth
What does it provide? Let's dig in.

What changed? #

We have a layout (resources/views/layouts/app.blade.php) that is the core of this scaffold, and then a series of views that extend it:
  • welcome.blade.php - the public welcome page
  • home.blade.php - the dashboard for logged-in users
  • auth/login.blade.php - the login page
  • auth/register.blade.php - the register/signup page
  • auth/passwords/email.blade.php - the password reset confirmation page
  • auth/passwords/reset.blade.php - the password reset prompt page
  • auth/emails/password.blade.php - the password reset email
Our public page is still routed via routes.php:
Route::get('/', function () {
    return view('welcome');
});
And we now have a HomeController, which routes our dashboard:
class HomeController extends Controller
{
    /**
     * Show the application dashboard.
     *
     * @return Response
     */
    public function index()
    {
        return view('home');
    }
}
This is of course routed in routes.php in the web group. And notice that there's something else new there: The Route::auth() method:
Route::group(['middleware' => 'web'], function () {
    Route::auth();

    Route::get('/home', '');
});

Route::auth() #

The auth() method is a shortcut to defining the following routes:
// Authentication Routes...
$this->get('login', '');
$this->post('login', '');
$this->get('logout', '');

// Registration Routes...
$this->get('register', '');
$this->post('register', '');

// Password Reset Routes...
$this->get('password/reset/{token?}', '');
$this->post('password/email', '');
$this->post('password/reset', '');

The frontend #

Now let's take a look at what we get in the browser:
Screenshot of the output from a default auth scaffold view
As you can see we have Bootstrap CSS, a basic Bootstrap app layout, and helpful to our basic auth actions.

App.blade.php #

So what does this master layout look like?
We get FontAwesome, the Lato font, Bootstrap CSS, a basic hamburger-on-mobile responsive layout, jQuery, Bootstrap JS, and placeholders that are commented out for the default output CSS and JS files if you choose to use Elixir.
We also have a top nav that links us home, and links guests to either login or register, and links authenticated users to log out.

Conclusion #

That's it! It's not anything complex, but it's 30-60 minutes of typing that you just saved on every app that needs it.

from : https://mattstauffer.co/blog/the-auth-scaffold-in-laravel-5-2

2016年11月25日 星期五

Middleware groups in Laravel 5.2

When you are creating a site of any significant size in Laravel, your routes file will often get pretty large. One of the first things I do in a new site is group my routes by logically distinct sections like "admin", "auth", "public". Usually each of these groups get their own set of middleware—admin, for example, gets auth. Maybe the API group gets a different auth middleware, and it might get an API-specific rate limiter or something else.
Laravel 5.2 has introduced something called middleware groups, which are essentially a shortcut to applying a larger group of middleware, using a single key.
Note: Even if you don't want to use the middleware "shortcuts" aspect of middleware groups, you should read on, because this is a big change to Laravel's global middleware stack.
So remember my admin example above? We can now create an "admin" middleware group. Let's learn how.

Defining middleware groups #

You can define middleware groups in app\Http\Kernel.php. There's a new property named $middlewareGroups that's an array; each key is a name and each value is the corresponding middleware.
Out of the box, it comes with web and api:
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],

    'api' => [
        'throttle:60,1',
    ],
];
As you can see, the keys can reference either a class or a route-specific middleware shortcut like throttle or auth. Let's make an admin group:
protected $middlewareGroups = [
    'web' => [...],
    'api' => [...],
    'admin' => [
        'web',
        'auth',
    ]
];
We've defined that the admin is a group that uses web (another group) and auth (a named route middleware). That's it!

Changes from 5.1 #

You might notice that the middleware in web are those that used to be applied to every route in Laravel 5.1 and before. That's a pretty big shift in thinking, so please take note of that: anything that's not given a web middleware will not have cookies or session or CSRF functional.
That also means we have a lot more flexibility, though: it frees us up to have more stateless API layers that aren't giving us the convenience of cookies and sessions. We can get rid of most of the universal middleware—if you take a look, the only universal middleware in 5.2 is the "check for maintenance mode" middleware.
Note as well that any APIs that rely on cookies or sessions (or CSRF) will not work if they're stuck under this api group, so if you have stateful APIs, you'll need to make some tweaks to this default apigroup.

Using middleware groups #

OK, so we know how to define a middleware group. How do we use it?
It'll be clear when you look at the default routes.php in 5.2:
Route::get('/', function () {
    return view('welcome');
});

Route::group(['middleware' => ['web']], function () {
    //
});
As you can see, you use it just like any route middleware like auth: just put the key either as the direct value of middleware, or in an array that's the value of middleware. So, here's our admin middleware group in use:
Route::group(['middleware' => 'admin'], function () {
    Route::get('dashboard', function () {
        return view('dashboard');
    });
});
That's it! Enjoy!
Note: Later in Laravel 5.2, all routes in routes.php are now wrapped with the webmiddleware group by default. I'll try to write that up more later, but take a look at the RouteServiceProvider to see how it's all working.

from : https://mattstauffer.co/blog/middleware-groups-in-laravel-5-2

API rate limiting in Laravel 5.2

More and more of my work in Laravel lately has been creating APIs. I have a manual rate limiter class I've been using, but I've had a sense that there's a cleaner way to do it. Unsurprisingly, when Taylor set out to write a rate limiter middleware for Laravel, he did it cleaner and better than I had.

Brief introduction to rate limiting #

If you're not familiar with it, rate limiting is a tool—most often used in APIs—that limits the rate at which any individual requester can make requests.
That means, for example, if some bot is hitting a particularly expensive API route a thousand times a minute, your application won't crash, because after the nth try, they will instead get a 429: Too Many Attempts. response back from the server.
Usually a well-written application that implements rate limiting will also pass back three headers that might not be on another application: X-RateLimit-LimitX-RateLimit-Remaining, and Retry-After(you'll only get Retry-After if you've hit the limit). X-RateLimit-Limit tells you the max number of requests you're allowed to make within this application's time period, X-RateLimit-Remaining tells you how many requests you have left within this current time period, and Retry-After tells you how many seconds to wait until you try again. (Retry-After could also be a date instead of a number of seconds).
Note: Each API chooses the time span it's rate limiting for. GitHub is per hour, Twitter is per 15-minute segment. This Laravel middleware is per minute.

How to use Laravel's rate-limiting middleware #

So, on to the new feature in Laravel 5.2. There's a new throttle middleware that you can use. Let's take a look at our API group:
Route::group(['prefix' => 'api'], function () {
    Route::get('people', function () {
        return Person::all();
    });
});
Let's apply a throttle to it. The default throttle limits it to 60 attempts per minute, and disables their access for a single minute if they hit the limit.
Route::group(['prefix' => 'api', 'middleware' => 'throttle'], function () {
    Route::get('people', function () {
        return Person::all();
    });
});
If you make a request to this api/people route, you'll now see the following lines in the response headers:
HTTP/1.1 200 OK
... other headers here ...
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
Remember, this response means:
A) This request succeeded (the status is 200)
B) You can try this route 60 times per minute
C) You have 59 requests left for this minute
What response would we get if we went over the rate limit?
HTTP/1.1 429 Too Many Requests
... other headers here ...
Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
And the actual content of the response would be a string: "Too Many Attempts."
What if we tried again after 30 seconds?
HTTP/1.1 429 Too Many Requests
... other headers here ...
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Same response, except the Retry-After timer that's telling us how long to wait has ticked down by 30 seconds.

Customizing the throttle middleware #

Let's do a bit of customization. We want to limit it to 5 attempts per minute.
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5'], function () {
    Route::get('people', function () {
        return Person::all();
    });
});
And if we want to change it so that, if someone hits the limit, they can't try again for another 10 minutes?
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5,10'], function () {
    Route::get('people', function () {
        return Person::all();
    });
});
That's all there is to it!
You can see the code that's supporting this here: ThrottlesRequests.php

from : https://mattstauffer.co/blog/api-rate-limiting-in-laravel-5-2

wibiya widget