User Authentication


##User Authentication

  • Introduction
    • Database Considerations
  • Quick Guide to User Authentication
    • Routing
    • View
    • Authentication
    • Retrieved Authenticated User
    • Path Protection
    • Login Restrictions
  • Manual Verify user
    • Remember user
    • Other authentication methods
  • HTTP Basic Authentication
    • Stateless HTTP Basic Authentication
  • Logout
    • Invalid sessions for other devices
  • Social authentication
  • Add custom protection
    • Turn off request protection
  • Add custom user provider
    • User Provider Contract
    • Certifiable Contract
  • Event

Introduction

{tip} Want to get started quickly? Just run php artisan make:auth and php artisan migrate in a new Laravel application. Then, navigate your browser to http://your-app.test/register or any other URL assigned to your application. These two commands will be responsible for building the entire authentication system!

Laravel makes implementing authentication very simple. In fact, almost all configurations are ready-made. The authentication configuration file is located at config/auth.php and contains several well-documented options for adjusting the behavior of the authentication service.

At its core, Laravel's authentication facility consists of "Guards" and "Providers". The guard decides how to authenticate the user for each request. For example, Laravel comes with a session protection, which uses session storage and cookies to maintain state.

The provider decides how to retrieve users from persistent storage. Laravel supports retrieving users using Eloquent and database query builder. However, you are free to define other providers based on your application's needs.

If this sounds confusing to you, don’t worry! Many applications never need to modify the default authentication configuration.

Database Notes

By default, Laravel includes an App\User Eloquent model is in your app directory. This model can be used with the default Eloquent authentication driver. If your application does not use Eloquent, you can use the database authentication driver, which uses the Laravel query builder.

When generating the database schema for the App\User model, make sure the password is at least 60 characters long. Keeping the default string length of 255 characters is a good choice.

Additionally, you should verify that the "users" (or equivalent) table contains a nullable, 100-character remember_token string. This column will be used to store the token when the user selects the "Remember Me" option when logging into the application.

Quick Guide to User Authentication

Laravel comes with several pre-built authentication controllers located in App\Http\Controllers\Auth namespace. RegisterController handles new user registration, LoginController handles authentication, ForgotPasswordController handles email links for resetting passwords, ResetPasswordController contains Logic to reset password. Each of these controllers uses an attribute to contain their necessary methods. For many applications, you don't need to modify these controllers at all.

Routing

Laravel provides a quick way to set up all the routes and views needed for authentication using a simple command:

php artisan make:auth

This command should be used for new applications program and will install layout views, registration and login views, and routes for all authentication endpoints. A HomeController will also be generated to handle post-login requests for the application dashboard.

{tip} If your application does not require registration, you can disable it by deleting the newly created RegisterController and modifying the route declaration: Auth::routes([' register' => false]);.

View

As mentioned in the previous section, php artisan make:auth The command will create all views required for authentication and place them in the resources/views/auth directory. The

make:auth command will also create a resources/views/layouts directory that contains the basic layout of the application. All these views use the Bootstrap CSS framework, but you are free to customize them.

Authentication

Now that the routing and views have been set up for the authentication controller, you can Register and authenticate new users! Because the controller already includes authentication logic by default to verify the user exists and save the user to the database (implemented through traits), you can now access the application in the browser.

Custom path

When users are authenticated successfully, they will be redirected to the URI /home. You can customize it by defining the redirectTo property in the LoginController, RegisterController, ResetPasswordController, and VerificationController controllers. Authenticated redirect location:

protected $redirectTo = '/';

Next, you should modify the handle method in the RedirectIfAuthenticated middleware to redirect to the new location when redirecting the user URI.

If the redirection path requires custom generation logic, you can define the redirectTo method instead of the redirectTo attribute:

protected function redirectTo(){ 
   return '/path';
 }

{Tip} The redirectTo method takes precedence over the redirectTo attribute.

Custom username

Laravel uses the email field for authentication by default. If you want to use other fields, you can define a username method in the LoginController controller:

public function username(){  
  return 'username';
 }

Customized Watcher

You can also customize the "Watcher" for user authentication and registration. To implement this functionality, guard methods need to be defined in LoginController, RegisterController and ResetPasswordController. This method will return a guard instance:

use Illuminate\Support\Facades\Auth;protected function guard(){ 
   return Auth::guard('guard-name');
 }

Custom verification/storage

In order to modify the form fields that new users need to fill in when registering, or customize How to store new users into the database, you can modify the RegisterController class. This class is responsible for validating and creating new users. The

validator

method of the RegisterController class contains the rules for validating new users. You can customize this method as you like. The

create

method of RegisterController is responsible for creating a new App\User record in the database using Eloquent ORM. You can customize this method according to the needs of the database.

Retrieve authenticated users

You can access authenticated users through the Auth facade :

use Illuminate\Support\Facades\Auth;
// 获取当前通过认证的用户...
$user = Auth::user();
// 获取当前通过认证的用户 ID...
$id = Auth::id();

Alternatively, you can access the authenticated user through the Illuminate\Http\Request instance. Don’t forget, the type-hinted class will be automatically injected into your controller method:

<?php
   namespace App\Http\Controllers;
   use Illuminate\Http\Request;
   class ProfileController extends Controller{ 
    /**
     * 更新用户资料。
     *
     * @param  Request  $request
     * @return Response
     */  
   public function update(Request $request)  
     {       
      // $request->user() 返回一个认证用户实例...   
      }
  }

To determine whether the current user has been authenticated

you can use ## The check method of the #Auth facade to check whether the user has been authenticated. If authenticated, true will be returned:

use Illuminate\Support\Facades\Auth;
if (Auth::check()) {   
 // 用户已经登录了...
}

{Tip} Although you can use the

check method to confirm whether the user is authenticated, the user will not be allowed to access before Before some route/controller, it is still common to use middleware to verify that the user is authenticated. For more information, check out the documentation on protected routing.

Protect routing

Routing middleware can be used to allow only authenticated users to access a given routing. Laravel comes with a

auth middleware, which is defined in Illuminate\Auth\Middleware\Authenticate. Since this middleware is already registered in the HTTP kernel, you only need to attach this middleware to the route definition:

Route::get('profile', function () {  
  // 只有认证过的用户可以进入...
 })->middleware('auth');

Of course, if you use a controller, you can call it in the controller's constructor

middleware Method to append it directly to the route definition:

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

Redirect unauthenticated users

When the auth middleware detects an unauthenticated user, it will redirect the user to a directory named login on named routes.
You can modify this behavior by modifying the redirectTo function in the app/Http/Middleware/Authenticate.php file:

/**
 * Get the path the user should be redirected to.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return string
 */
 protected function redirectTo($request){ 
    return route('login');
 }

Specify the watcher

When you add the auth middleware to the route, you can also specify which watcher to use for user authentication. The specified guard should correspond to a key in the guards array in the auth.php configuration file:

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

Login Throttling

If you use Laravel's built-in LoginController class, the Illuminate\Foundation\Auth\ThrottlesLogins trait is already included in the control The device was hit. By default, if a user fails to provide correct login credentials after multiple attempts, the user will not be able to try to log in again for one minute. This throttling policy is based on the uniqueness of a user's username/email address and their IP address.

Manually authenticating users

It is not necessary to use an authentication controller in Lavarel. If you choose to remove these controllers, you will need to use the Lavarel validation classes directly. Don't worry, it's easy!

You can access the Laravel service with the help of the Auth facade, so you need to import Auth at the beginning of the class. Let's take a look at the attempt method:

<?php
    namespace App\Http\Controllers;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    class LoginController extends Controller{  
     /**
     * 处理身份验证尝试。
     *
     * @param  \Illuminate\Http\Request $request
     *
     * @return Response
     */   
    public function authenticate(Request $request)   
     {       
        $credentials = $request->only('email', 'password');      
        if (Auth::attempt($credentials)) {        
            // 身份验证通过...           
           return redirect()->intended('dashboard');    
             }   
           }
        }

attempt Each parameter of the method is an associative array. The array value is used to find the user in the database. In the above example, the user will be found by the value of the email column. If the user is found, the hashed password stored in the database is compared to the password value in the array. There is no need to hash password, the framework automatically hashes this value before comparing it to the hashed password in the database. If the two hashes match, an authenticated session will be established for the user.

If the verification is successful, the attempt method returns true, otherwise it returns false.

The intended method in redirection will redirect the user to the URL intercepted before authentication via the authentication middleware. If the expected target does not exist, you can specify a fallback URI for this method.

Specify additional conditions

In addition to the user's email and password, you can add additional conditions to the authentication query. For example, we can verify that the user has been marked as "activated":

if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {  
  // 用户存在,已激活且未被禁用。
 }

{note} In these examples, email is not a required option, it is only used Demonstrate. You should use column names that correspond to "username" in your database.

Access the specified guard instance

You can use the Auth facade's guard method to specify the guard instance you want to use. This allows you to use completely independent verifiable models or user tables to manage validation for various parts of your application.

The guard name passed to the guard method needs to match one of the configuration items in the auth.php configuration:

if (Auth::guard('admin')->attempt($credentials)) { 
   //
 }

Logout

Users need to log out using the logout method of the Auth facade. It will clear the user authentication information in the user session:

Auth::logout();

Remember the user

If you want To provide "remember me" functionality in your application, you can pass a boolean value to the attempt method as its second parameter, which will keep the user authenticated indefinitely until the user manually logs out. The user table needs to contain a remember_token column of string type for storing tokens.

if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) { 
   // 用户被记住...
}

{tip} If you use Laravel's built-in LoginController, the correct logic to "remember" the user is already implemented by the traits used by the controller.

If "Remember User" is enabled, you can use the viaRemember method to determine whether the "Remember Me" cookie is used to authenticate the user:

if (Auth::viaRemember()) { 
   //
}

Other authentication methods

Verify user instance

If you want to replace an existing To log in to the application, the user can call the login method with the user instance as its parameter. The object must implement the Illuminate\Contracts\Auth\Authenticatable contract. The App\User model that comes with Laravel has implemented this interface:

Auth::login($user);
// 登录并「记住」给定的用户...
Auth::login($user, true);

Use the following method to specify the desired guard instance:

Auth::guard('admin')->login($user);

Verify user identity by ID

You can use the loginUsingId method to log in the user to the application by ID. This method accepts the primary key of the user whose identity you wish to authenticate:

Auth::loginUsingId(1);
// 登录并「记住」给定用户...
Auth::loginUsingId(1, true);

Authenticate the user's identity only once

You can use the once method to authenticate the user in a single request The user logs into the application. Doing so will not use sessions or cookies, which means this method helps build a stateless API:

if (Auth::once($credentials)) {
    //
  }

HTTP Basic Authentication

HTTP Basic Authentication Provides a quick way to authenticate users in your application without setting up a dedicated "login" page. Before you begin, attach the auth.basic middleware to your route. auth.basic The middleware is already included in the Laravel framework, so you don't need to define it:

Route::get('profile', function () { 
   // 只有认证过的用户可以进入...
 })->middleware('auth.basic');

After attaching the middleware to a route, it will automatically You are prompted for credentials. By default, the auth.basic middleware uses the email field on the user record as the "username".

FastCGI Notes

If you are using PHP FastCGI mode, HTTP basic authentication may not work properly. You need to add the following lines to your .htaccess file:

RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

##Stateless HTTP Basic Authentication

You can also use HTTP basic authentication without setting the user identifier cookie in the session, which is especially useful for API authentication. To do this, define a middleware that will call the

onceBasic method. If the onceBasic method does not return any response, the request can be passed further into the application:

<?php
  namespace App\Http\Middleware;
  use Illuminate\Support\Facades\Auth;
  class AuthenticateOnceWithBasicAuth{   
       /**
     * 处理传入的请求
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */  
  public function handle($request, $next)  
    {       
       return Auth::onceBasic() ?: $next($request);  
     }
   }

Next, the routing middleware is registered and attached to the route:

Route::get('api/user', function () {  
  // 只有认证过的用户可以进入...
})->middleware('auth.basic.once');

Logout

To manually log the user out of the application, you can use the

Auth facade logout method. This will clear the authentication information in the user's session:

use Illuminate\Support\Facades\Auth;Auth::logout();

Invalidate the Session on other devices

Laravel A mechanism is also provided for invalidating and "logging off" user sessions on other devices without invalidating the session on their current device. First, you need to ensure that the

Illuminate\Session\Middleware\AuthenticateSession middleware is in the web middleware group in your app/Http/Kernel.php class , and is not commented out:

'web' => [   
    // ...
    \Illuminate\Session\Middleware\AuthenticateSession::class,  
    // ...
  ],

Then, you can use the

logoutOtherDevices method on the Auth facade. This method requires the user to provide their current password, which your application should accept through the input form:

use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);

{note} When the

logoutOtherDevices method is called, the user's other Session will be completely disabled, meaning they will "exit" all of the watchers they were previously authenticated to.

Add a custom guard

You can define your own authentication guard using the extend method of the Auth facade. You should call the extend method in the service provider. Since Laravel already comes with AuthServiceProvider, we can put the code in that provider:

<?php
  namespace App\Providers;
  use App\Services\Auth\JwtGuard;
  use Illuminate\Support\Facades\Auth;
  use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
  class AuthServiceProvider extends ServiceProvider{   
      /**
     * 注册任意应用认证/授权服务。
     *
     * @return void
     */   
  public function boot()  
   {      
     $this->registerPolicies();        
     Auth::extend('jwt', function ($app, $name, array $config) {         
       // 返回一个 Illuminate\Contracts\Auth\Guard 实例...           
        return new JwtGuard(Auth::createUserProvider($config['provider']));     
         });   
    }}

As you can see in the example above, pass to extend The callback of the method should return an instance that implements the Illuminate\Contracts\Auth\Guard interface. This interface contains some methods that you need to implement in your custom watcher. After your custom guard is defined, you can use this guard in the guards configuration of the auth.php configuration file:

'guards' => [  
  'api' => [     
     'driver' => 'jwt',        
     'provider' => 'users',    
     ],
  ],

Request Closure Guard

The simplest way to implement a custom authentication system based on HTTP requests is to use Auth::viaRequest method. This method allows you to quickly define the authentication process using a single closure.

First, call the Auth::viaRequest method in the boot method of AuthServiceProvider. viaRequest The method accepts a guard name as its first parameter. This name can be any string that describes your custom watcher. The second argument passed to this method should be a closure function that receives the incoming HTTP request and returns a user instance, or null if validation fails:

use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
  /**
 * 注册任意应用认证/授权服务。
 *
 * @return void
 */
 public function boot(){  
   $this->registerPolicies();  
    Auth::viaRequest('custom-token', function ($request) {     
       return User::where('token', $request->token)->first();  
       });
     }

When you have finished customizing the guard, you can use this guard in the guards configuration of the auth.php configuration file:

'guards' => [   
 'api' => [      
   'driver' => 'custom-token',  
   ],
 ],

Add a custom user provider

If you are not using a traditional relational database to store users, you will need to extend Lavarel with your own authentication user provider . You can customize the user provider using the provider method of the Auth facade:

<?php
    namespace App\Providers;
    use Illuminate\Support\Facades\Auth;
    use App\Extensions\RiakUserProvider;
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
    class AuthServiceProvider extends ServiceProvider{   
        /**
     * 注册任意应用身份验证 / 授权服务Register any application authentication / authorization services.
     *
     * @return void
     */   
      public function boot()   
       {      
         $this->registerPolicies();       
         Auth::provider('riak', function ($app, array $config) {         
            // 返回 Illuminate\Contracts\Auth\UserProvider 实例...            
            return new RiakUserProvider($app->make('riak.connection'));       
           });   
        }}

Once registered using the provider method, you can auth.php Switch to the new user provider in the configuration file. First define a provider that uses the new driver:

'providers' => [  
  'users' => [      
    'driver' => 'riak',  
      ],
  ],

Then you can use this provider in the guards configuration:

'guards' => [   
    'web' => [     
       'driver' => 'session',        
       'provider' => 'users',    
     ],
  ],

User Provider Contract

Illuminate\Contracts\Auth\UserProvider The implementation is only responsible for extracting from persistent storage systems such as MySQL, Riak, etc. Illuminate\Contracts\Auth\Authenticatable accomplish. These two interfaces allow Laravel's authentication mechanism to continue functioning regardless of how the user is stored and what type of class is used to represent it:

Let's take a lookIlluminate\Contracts\Auth\UserProvider Contract:

<?php
    namespace Illuminate\Contracts\Auth;
    interface UserProvider {  
      public function retrieveById($identifier);    
      public function retrieveByToken($identifier, $token);    
      public function updateRememberToken(Authenticatable $user, $token);    
      public function retrieveByCredentials(array $credentials);    
      public function validateCredentials(Authenticatable $user, array $credentials);
     }

retrieveById The function usually accepts the key used to represent the class (such as the automatically incremented ID in the MySQL database) as a parameter, and obtains and returns the ## matching this ID #Authenticatable implementation. The

retrieveByToken function retrieves a user using their unique $identifier and the "remember me" token stored in the remember_token column. Like the previous method, it returns the Authenticatable implementation. The

updateRememberToken method updates the remember_token column of $user with the new $token. A "refresh token" is assigned when the "Remember Me" login verification is successful or when the user logs out.

The

retrieveByCredentials method accepts an array of credentials passed to the Auth::attempt method when attempting to log in to the application. This method "queries" the underlying persistence store for users matching these credentials. Typically, this method runs a "where" condition based on $credentials['username'], which should return an Authenticatable implementation. This method does not attempt any password verification or authentication. The

validateCredentials method should compare the given $user to $credentials to validate the user's identity. For example, this method should probably use Hash::check to compare the value of $user->getAuthPassword() with that of $credentials['password'] value. It should return true or false to indicate whether the user's password is valid.

Authentication Contract

We have dissected each method of UserProvider. Let’s take a look at the Authenticatable contract. Remember that the user provider's retrieveById, retrieveByToken, and retrieveByCredentials methods will return an instance of this interface:

<?php
   namespace Illuminate\Contracts\Auth;
   interface Authenticatable {   
      public function getAuthIdentifierName();    
      public function getAuthIdentifier();    
      public function getAuthPassword();    
      public function getRememberToken();    
      public function setRememberToken($value);    
      public function getRememberTokenName();
     }

This interface is simple. The getAuthIdentifierName method should return the name of the user's "primary key" column, and the getAuthIdentifier method should return the user's "primary key". In the MySQL backend, it will be an auto-incrementing primary key. getAuthPassword The method should return the user's hashed password. This interface allows the authentication system to always work with any User class, regardless of which ORM or abstraction storage layer is used. By default, Laravel's app directory will contain a User class that implements this interface. You can use this implementation example as a reference.

Events

Laravel raises a variety of events during the authentication process. Listeners for these events can be attached in EventServiceProvider:

/**
 * 应用的事件监听器映射。
 *
 * @var array
 */
 protected $listen = [   
    'Illuminate\Auth\Events\Registered' => [     
       'App\Listeners\LogRegisteredUser',  
       ],  
     'Illuminate\Auth\Events\Attempting' => [     
        'App\Listeners\LogAuthenticationAttempt', 
         ],  
      'Illuminate\Auth\Events\Authenticated' => [    
         'App\Listeners\LogAuthenticated',   
        ],  
      'Illuminate\Auth\Events\Login' => [     
         'App\Listeners\LogSuccessfulLogin',   
        ],  
      'Illuminate\Auth\Events\Failed' => [     
         'App\Listeners\LogFailedLogin',   
        ], 
      'Illuminate\Auth\Events\Logout' => [      
           'App\Listeners\LogSuccessfulLogout',  
           ],   
       'Illuminate\Auth\Events\Lockout' => [     
         'App\Listeners\LogLockout',   
         ],  
       'Illuminate\Auth\Events\PasswordReset' => [     
         'App\Listeners\LogPasswordReset',   
         ],
      ];
This article was first published on the LearnKu.com website.