Laravel5.1用户验证

Published on 2017 - 04 - 02

Configuration Laravel Authentication

The config/auth.php file houses Laravel’s authentication settings. In most cases you can leave the default settings untouched, however let’s review the settings so you have a clear understanding of what’s available:

  • driver: This setting determines how users will be retrieved and authenticated. It’s set to eloquent, meaning there are certain expectations such as the use of a model for managing the user and credentials. The other supported driver, database, causes Laravel to instead directly interact with the database rather than do so through a model. Unless you know what you’re doing I suggest sticking with Eloquent.
  • model: This setting tells Laravel what model will be used to maintain the user information (e-mail address, password, remember token). By default it’s set to App\User. Why this is so will become clear later in the chapter.
  • table: This setting identifies the database table used to store the user information (e-mail address, password, remember token, etc.). By default it’s set to users. As with the model default setting, you’ll soon understand why the Laravel developers chose this particular value.
  • password: Laravel 5 stubs out some of the infrastructure required to manage and process password recovery requests. This setting identifies the view containing the content of the e-mail sent to requesting users, the database table used to manage the password recovery requests, and the number of minutes before the password recovery requests become invalid.

Registering Users

Implementing the user registration feature seems to be a particularly logical place to begin. Although it’s fairly straightforward, this section is easily the longest in the chapter because there are a few other matters I necessarily need to introduce, beginning with the model used to manage the user accounts.

Introducing the User Model

The Laravel developers have saved you the hassle of building the model used to manage user accounts, placing a User model in the app directory.

 <?php

 namespace App;

 use Illuminate\Auth\Authenticatable;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Auth\Passwords\CanResetPassword;
 use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
 use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

 class User extends Model implements AuthenticatableContract, 
   CanResetPasswordContract
 {
     use Authenticatable, CanResetPassword;

     protected $table = 'users';

     protected $fillable = ['name', 'email', 'password'];

     protected $hidden = ['password', 'remember_token'];
 }

This User model looks rather different, notably because in addition to extending the Model class it implements two contracts, including AuthenticatableContract and CanResetPasswordContract. A contract defines an interface to a particular implementation of a set of features. For instance, AuthenticatableContract defines an interface for obtaining the user’s unique identifier and password and for managing the “remember me” token should it be enabled. Because the interface ensures the functionality is loosely coupled, you’re free to easily swap out the Laravel implementation for another.

The contracts work in unison with the traits (a feature new to PHP as of version 5.4). As you can see, the User model uses two traits, including Authenticatable and CanResetPassword. Traits offer a useful alternative to multiple inheritance (something PHP can’t do natively), allowing you to inherit methods from several different classes, thereby avoiding code duplication. Therefore the contract defines the interface, and the trait identifies the interface implementation. You could of course swap out the implemented traits for your own implementations, provided you meet the requirements defined in the contract.

The $fillable property identifies the columns that can be inserted/updated by way of mass assignment. Finally, the $hidden property is used to identify columns that should not be passed into JSON or arrays. Logically we don’t want to expose the password (even if in hashed format) nor the session remember token, and so these are identified in the $hidden property.

Introducing the Users Table

In addition to creating the User model, the Laravel developers also created the corresponding users table migration, which you’ll find in database/migrations/2014_10_12_000000_create_users_table.php. The table looks like this:

 mysql> describe users;
 +----------------+------------------+------+-----+...
 | Field          | Type             | Null | Key |...
 +----------------+------------------+------+-----+...
 | id             | int(10) unsigned | NO   | PRI |...
 | name           | varchar(255)     | NO   |     |...
 | email          | varchar(255)     | NO   | UNI |...
 | password       | varchar(60)      | NO   |     |...
 | remember_token | varchar(100)     | YES  |     |...
 | created_at     | timestamp        | NO   |     |...
 | updated_at     | timestamp        | NO   |     |...
 +----------------+------------------+------+-----+...
 7 rows in set (0.01 sec)

Fortunately, you won’t have to construct any custom logic to interact with this table, because it’s already in place! Read on to learn more.

Introducing the Account Registration Feature

Laravel 5.0 included several convenient registration-related routes in app/Http/routes.php, however these were inexplicably removed with the version 5.1 release. You can however easily add them back:

Route::get('auth/register', 'Auth\AuthController@getRegister');
Route::post('auth/register', 'Auth\AuthController@postRegister');

The Auth controller is responsible for managing both new user registration and user authentication. You’ll find this controller in app/Http/Controllers/Auth/AuthController.php.

With the routes in place, you’ll next need to create the registration view. An example view was included by default with Laravel 5.0 applications but was removed as of version 5.1. Creating one is easy however provided you name it register.blade.php and place it inside a directory named auth found in resources/views. Here is an example, Bootstrap-stylized form (which also takes advantage of the LaravelCollective/Html form facade):

 @extends('layouts.master')

 @section('content')
 <div class="col-md-6">
 {!! Form::open(array('url' => '/auth/register', 'class' => 'form')) !!}

 <h1>Create a TODOParrot Account</h1>

 @if (count($errors) > 0)
   <div class="alert alert-danger">
     There were some problems creating an account:
    <ul>
       @foreach ($errors->all() as $error)
               <li>{{ $error }}</li>
       @endforeach
     </ul>
   </div>
 @endif

 <div class="form-group">
     {!! Form::label('name', 'Your Name') !!}
     {!! Form::text('name', null, array('class'=>'form-control', 'placeholder'=>'\
 Name')) !!}
 </div>
 <div class="form-group">
     {!! Form::label('Your E-mail Address') !!}
     {!! Form::text('email', null, 
       array('class'=>'form-control', 'placeholder'=>'Email Address')) !!}
 </div>
 <div class="form-group">
     {!! Form::label('Your Password') !!}
     {!! Form::password('password', 
       array('class'=>'form-control', 'placeholder'=>'Password')) !!}
 </div>
 <div class="form-group">
     {!! Form::label('Confirm Password') !!}
     {!! Form::password('password_confirmation', 
       array('class'=>'form-control', 'placeholder'=>'Confirm Password')) !!}
 </div>

 <div class="form-group">
     {!! Form::submit('Create My Account!', 
       array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}
 </div>
 @endsection

After saving this view, you’ll be able to access the registration form by navigating to /auth/register. The rendered form is presented in the below screenshot.

Go ahead and register, and you’ll see that a new record will be inserted into the users table. Further, Laravel will automatically sign you into the site and attempt to redirect to the /home URI. If this URI doesn’t exist then you’ll receive a 404 error. You can either define the route in your routes file, or you can override the destination URI by overriding the $redirectTo property within the AuthController.php file:

protected $redirectTo = '/';

Introducing the Account Sign In Feature

Like user registration, Laravel applications include all of the logic required to authenticate registered users, however as of version 5.1 you’ll need to do a bit of additional work to integrate the feature into your application. Begin by adding the following two routes to your routes.php file:

Route::get('auth/login', 'Auth\AuthController@getLogin');
Route::post('auth/login', 'Auth\AuthController@postLogin');

Next, create a file named login.blade.php inside resources/views/auth, and add the following contents to it:

 @extends('layouts.master')

 @section('content')
 <div class="col-md-6">

 {!! Form::open(array('url' => '/auth/login', 'class' => 'form')) !!}

   <h1>Sign In to Your TODOParrot Account</h1>

   @if (count($errors) > 0)

     <div class="alert alert-danger">
       There were some problems signing into your account:
       <ul>
         @foreach ($errors->all() as $error)
           <li>{{ $error }}</li>
         @endforeach
       </ul>
     </div>

   @endif

   <div class="form-group">
     {!! Form::label('email', 'Your E-mail Address') !!}
     {!! Form::text('email', null, 
       array('class'=>'form-control', 'placeholder'=>'E-mail')) !!}
   </div>

   <div class="form-group">
     {!! Form::label('Your Password') !!}
     {!! Form::password('password', 
       array('class'=>'form-control', 'placeholder'=>'Password')) !!}
   </div>

   <div class="form-group">
     <label>
       {!! Form::checkbox('remember', 'remember') !!} Remember Me
     </label>
   </div>

   <div class="form-group">
     {!! Form::submit('Login', array('class'=>'btn btn-primary')) !!}
   </div>

   <a href="/password/email">Forgot Your Password?</a>
   </div>
   </div>
 {!! Form::close() !!}

 </div>
 @endsection

With the routes and view in place, you can navigate to /auth/login to see and use the sign in form. If you used the above code you’ll see the form presented in the below screenshot.

Go ahead and sign in using the account you created in the last section, and as before you’ll be redirected to the Home controller. Like the registration form, you can easily modify the sign in view to suit your needs by editing the view found at resources/views/auth/login.blade.php.

Remember from the earlier registration-related discussion that successfully authenticated users will be redirected to the /home URI default. You can either define a route in routes.php, or override the default redirection URL by adding the following property to the Auth controller (found in app/Http/Controllers/Auth/AuthController.php):

protected $redirectPath = '/';

Signing Out of an Account

All Laravel applications include the ability to end an authenticated session by signing the user out of his account. To enable this feature (as of version 5.1) you’ll need to add the following route to your routes.php file:

Route::get('auth/logout', 'Auth\AuthController@getLogout');

Password Recovery

All Laravel applications include password recovery/reset logic however as of version 5.1 you’ll need to complete some additional work to integrate the feature into your application. Begin by adding the following routes to routes.php:

 Route::get('password/email', 'PasswordController@getEmail');
Route::post('password/email', 'PasswordController@postEmail');

Route::get('password/reset/{token}', 'PasswordController@getReset');
Route::post('password/reset', 'PasswordController@postReset');

Next you’ll need to create a view named password.blade.php, adding it to resources/views/auth. Here’s an example view:

 @extends('layouts.master')

 @section('content')
 <div class="col-md-6">

 {!! Form::open(array('url' => '/password/email', 'class' => 'form')) !!}

 <h1>Recover Your Password</h1>

 @if (count($errors) > 0)
   <div class="alert alert-danger">
     There were some problems recovering your password:
     <br />
     <ul>
         @foreach ($errors->all() as $error)
             <li>{{ $error }}</li>
         @endforeach
     </ul>
   </div>
 @endif

 <div class="form-group">
   {!! Form::label('email', 'Your E-mail Address') !!}
   {!! Form::text('email', null, 
     array('class'=>'form-control', 'placeholder'=>'E-mail')) !!}
</div>

 <div class="form-group">
   {!! Form::submit('E-mail Password Reset Link', 
     array('class'=>'btn btn-primary')) !!}
 </div>
 {!! Form::close() !!}
 </div>
 @endsection

Next, you’ll need to create the e-mail text which is sent to the user after submitting the form. You must name this view password.blade.php and place it in the directory resources/views/emails. Here is an example view:

Dear User,

Oh noes! You've forgotten your password. No big deal, 
click on the following URL to reset it:

{{ url('password/reset/'.$token) }} 

With the route and views in place, you can navigate to /password/email and you’ll see the form presented in the below screenshot:

Once submitted, if the supplied e-mail address matches a record found in the users table, a record such as the following is added to the password_resets table:

mysql> select * from password_resets;
+------------------+--------------------+---------------------+
| email            | token              | created_at          |
+------------------+--------------------+---------------------+
| wj@wjgilmore.com | asdfasfaasfasfasdf | 2015-06-08 19:26:02 |
+------------------+--------------------+---------------------+
1 row in set (0.00 sec)

In addition to updating the password_resets table, an e-mail will be sent to the e-mail address supplied by the requesting user. This e-mail will contain a link to the password recovery interface, and will include the recovery token found in the password_resets table. When the user clicks this link he’ll be able to choose a new password. The default recovery e-mail is quite sparse, however you can update it to include whatever additional information you please by modifying the file resources/views/emails/password.blade.php.

The recovering user will have 60 minutes to click on the recovery link per the config/auth.php file’s password['expire'] setting. Obviously you can change this setting to whatever value you desire. For instance to give users up to 24 hours to recover the password, you’ll set expire to 1440.

Retrieving the Authenticated User

You can retrieve the users record associated with the authenticated user via Auth::user(). For instance, to retrieve the user’s name you’ll access Auth::user() like so:

Welcome back, {{ Auth::user()->name }}!

Of course, you’ll want to first ensure the user is authenticated before attempting to access the record in this fashion. You can do so by consulting Auth::check():

@if (Auth::check())
  Welcome back, {{ Auth::user()->name }}! 
@else
  Hello, stranger! <a href="/auth/login">Login</a> 
  or <a href="/auth/register">Register</a>.
@endif 

Conversely, you can flip the conditional around, instead Auth::guest() to determine if the user is a guest:

@if (Auth::guest())
  <li><a href="/auth/login">Login</a></li>
  <li><a href="/auth/register">Register</a></li>
@else
  Welcome back, {{ Auth::user()->name }}!
@endif

Restricting Access to Authenticated Users

As I briefly discussed in the earlier section, “Introducing the Account Registration Feature”, you can easily restrict access to a controller by referencing the auth middleware in the appropriate controller constructor:

public function __construct()
{
  $this->middleware('auth');
}

When users attempt to access the restricted controller, Laravel will first check for a valid session. If the session exists, access to the controller will be granted; otherwise the user will be redirected to the sign in view.

Restricting Forms to Authenticated Users

 <?php namespace todoparrot\Http\Requests;

 use todoparrot\Http\Requests\Request;

 class ContactFormRequest extends Request {

   public function authorize()
   {
     return false;
   }

   ...

 }

If you’d like to restrict a form request to authenticated users, you can modify the authorize() method to look like this:

public function authorize()
{
  return Auth::check();
}

Keep in mind you’re free to embed into authorize() whatever logic you deem necessary to check a user’s credentials. For instance if you wanted to restrict access to not only authenticated users but additionally only those who are paying customers, you can retrieve the user using Auth::user() and then traverse whatever associations are in place to determine the user’s customer status.

Creating Route Aliases

Next we’ll need to define routes for displaying the registration form and then processing the form submission. Open app/routes.php and add the following lines:

 get('/signup', array('as' => 'signup', 
  'uses' => 'Auth\AuthController@getRegister'));
post('/signup', array('as' => 'signup', 'uses' => 'Auth\AuthController@postRegister'));

After saving the changes you should be able to navigate to /signup and see the registration form.

Reference