This article mainly introduces the Laravel user authentication system Implementation details, has a certain reference value, now share to everyone, the need for friends can refer to
Implementation details of the user authentication system
In the previous section we introduced the basics of the Laravel auth system, describing what constitutes his core components, and this section focuses on the implementation details of the Laravel auth system, with a focus on Auth
AuthManager
How to load a Certified Gatekeeper (guard) and user provider (Userprovider) and the implementation details of the default user registration and login, by combing through these implementation details we will be able to know how to customize the Auth certification to meet the user certification requirements of our own projects.
Loading watchmen and user providers via AuthManager
AuthManager loading watchmen and user-supplied to the method is more, with the text description is not very clear, we use the process of annotating the method to see the specific implementation details.
Namespace Illuminate\auth;class AuthManager implements factorycontract{/** * Try to get the specified guard from the $guards attribute * * @ param string $name * @return \illuminate\contracts\auth\guard|\illuminate\contracts\auth\statefulguard */Pub Lic function Guard ($name = null) {$name = $name?: $this->getdefaultdriver (); return Isset ($this->guards[$name])? $this->guards[$name]: $this->guards[$name] = $this->resolve ($name); /** * resolves the Guard * * @param string $name * @return \illuminate\contracts\auth\guard|\illum of the given name Inate\contracts\auth\statefulguard * * @throws \invalidargumentexception */protected function Resolve ($nam e) {//Get the configuration of the guard//$config = [' driver ' + ' session ', ' provider ' + ' users '] $config = $this ->getconfig ($name); if (Is_null ($config)) {throw new InvalidArgumentException ("Auth guard [{$name}] is not defined. "); If the drive is defined for guard by the Extend method, go here to call the custom guard drive if (isset ($this->customcreators[$config [' Driver '])) {R Eturn $this->callcustomcreator ($name, $config); //laravel Auth The default configuration here is to perform createsessiondriver $driverMethod = ' Create '. Ucfirst ($config [' Driver ']). ' Driver '; if (Method_exists ($this, $driverMethod)) {return $this->{$driverMethod} ($name, $config); } throw new InvalidArgumentException ("Auth guard driver [{$name}] is not defined."); /** * Configuration of the guard with the given name from config/auth.php * * @param string $name * @return Array */' guard s ' = = [' web ' = [' driver ' + ' session ', ' provider ' = ' users ',], ' API ' = [' Driver ' = ' token ', ' provider ' = ' users ',], protected functi On GetConfig ($name) {//' guards ' = + [//' web ' = + [//' Driver ' = ' session ',//' provider ' + ' users ',//],//' API ' = [// ' Driver ' = ' token ',//' provider ' + ' users ',//],//],//under Laravel The auth configuration, this method will get the key "Web" corresponding to the array return $this->app[' config '] ["auth.guards.{ $name} "]; /** * Call the Custom guard drive * * @param string $name * @param array $config * @return Mixed * /protected function Callcustomcreator ($name, array $config) {return $this->customcreators[$config [' Drive R ']] ($this->app, $name, $config); }/** * Register a custom closure guard drive to the customcreators attribute * * @param string $driver * @param \closure $cal Lback * @return $this */Public Function extend ($driver, Closure $callback) {$this->customcreator s[$driver] = $callback; return $this; }/** * Register a custom user provider creator into the customprovidercreators attribute * * @paramString $name * @param \closure $callback * @return $this */Public Function provider ($name, Closure $cal Lback) {$this->customprovidercreators[$name] = $callback; return $this; /** * Create session-based authentication keeper Sessionguard * * @param string $name * @param array $config * @re Turn \illuminate\auth\sessionguard */Public Function createsessiondriver ($name, $config) {//$config [' PR Ovider '] = = ' users ' $provider = $this->createuserprovider ($config [' Provider ']?? null); $guard = new Sessionguard ($name, $provider, $this->app[' Session.store '); if (method_exists ($guard, ' Setcookiejar ')) {$guard->setcookiejar ($this->app[' cookie '); } if (Method_exists ($guard, ' Setdispatcher ')) {$guard->setdispatcher ($this->app[' events '); } if (Method_exists ($guard, ' setrequest ')) {$guard->setrequest ($this->app->refresh ('Request ', $guard, ' setrequest '); } return $guard; }//Create guard driver dependent user Provider object public Function Createuserprovider ($provider = null) {if (Is_null ($config = $ This->getproviderconfiguration ($provider))) {return; }//If the custom user-provider creator closure is registered through Auth::p Rovider method, the call closure gets the user-provider object if (Isset ($this->customprovidercreators[$dri ver = ($config [' Driver ']?? null)])) {return Call_user_func ($this->customprovidercreators[$ Driver], $this->app, $config); } switch ($driver) {case ' database ': Return $this->createdatabaseprovider ($config); Case ' eloquent '://through the default Auth configuration this will return the Eloquentuserprovider object, which implements the Illuminate\contracts\auth interface return $this->createeloquentprovider ($config); Default:throw New InvalidArgumentException ("Authentication user provider [{$driver}] I SNot defined. ");}} /** * __call to dynamically invoke AuthManager Agent's Guard user authentication related method * According to the default configuration, here __call will call the method in Sessionguard * @param string $met Hod * @param array $parameters * @return Mixed */Public function __call ($method, $parameters) { return $this->guard ()->{$method} (... $parameters); }}
Registered users
The default enrollment routes in the Laravel auth system are as follows:
$this->post (' register ', ' Auth\registercontroller@register ');
So the logic of the user registration is done by the Registercontroller register method.
class Registercontroller extends controller{//method defined in illuminate\foundation\ Auth\registerusers Public Function Register (Request $request) {$this->validator ($request->all ()) Validate (); Event (new registered ($user = $this->create ($request->all ())); $this->guard ()->login ($user); return $this->registered ($request, $user)} Protected function Validator (array $data) {R Eturn Validator::make ($data, [' name ' = ' required|string|max:255 ', ' email ' = ' Required|strin G|email|max:255|unique:users ', ' password ' = ' required|string|min:6|confirmed ',]); } protected function Create (array $data) {return user::create ([' name ' = = $data [' name '], ' Email ' and $data [' email '], ' password ' + bcrypt ($data [' Password ']); } }
Register process is very simple, is to verify that the user input data is not a problem to write this data to the database generation user, where password encryption using the BCRYPT algorithm, If you need to change to the usual salt and password plaintext password encryption method can be in the Create method to change this part of the logic, after registering the user will call Sessionguard login method to load the user data into the application, note that the login method does not login authentication , just load the authenticated user into the app so that we can get the user data anywhere in the app Auth::user()
.
User Login Authentication
The login routes for the Laravel auth system are as follows
$this->post (' login ', ' auth\logincontroller@login ');
Let's take a look at the login logic in Logincontroller.
Class Logincontroller extends controller{/** * Processing Login Request */Public Function login (Request $request) { Verify the Login field $this->validatelogin ($request); Prevent malicious multiple logon attempts if ($this->hastoomanyloginattempts ($request)) {$this->firelockoutevent ($request); return $this->sendlockoutresponse ($request); }//Login authentication if ($this->attemptlogin ($request)) {return $this->sendloginresponse ($request); } $this->incrementloginattempts ($request); return $this->sendfailedloginresponse ($request); }//try to login authentication protected function Attemptlogin (Request $request) {return $this->guard ()->attempt ( $this->credentials ($request), $request->filled (' remember ')); }//Get the field value for login protected function credentials (Request $request) {return $request->only ($this->us Ername (), ' Password '); }}
The
can see that the logic of login authentication is implemented through the attempt
method of Sessionguard
, which is actually auth::attempt ()
, Let's take a look at the logic in the attempt
method:
class Sessionguard implements Statefulguard, supportsbasicauth{public function attempt (array $credentials = [], $remember = False) {$this->fireattemptevent ($credentials, $remembe R); $this->lastattempted = $user = $this->provider->retrievebycredentials ($credentials); If the login authentication is passed, the user object is loaded into the application via the login method ($this->hasvalidcredentials ($user, $credentials)) {$this->log In ($user, $remember); return true; }//Login failure, you can trigger an event to notify the user of suspicious login attempts (need to define listener to implement) $this->firefailedevent ($user, $credentials); return false; } protected function Hasvalidcredentials ($user, $credentials) {return! Is_null ($user) && $this- >provider->validatecredentials ($user, $credentials); }}
sessionguard
attempt
method first through the user provider's retrivebycredentials
Method through user name from the user table to query the user data, authentication user information is through the user provider's validatecredentials
to implement, all the user provider implementation class will implement the Userprovider contract ( Interface) The method defined in the above analysis we know that the default user provider is eloquentuserprovider
Class Eloquentuserprovider implements userprovider{remove the user instance from the database public function retrievebycredentials (array $credent IALs) {if (empty ($credentials) | | (count ($credentials) = = = 1 && array_key_exists (' password ', $credentials))) {return; } $query = $this->createmodel ()->newquery (); foreach ($credentials as $key = + $value) {if (! Str::contains ($key, ' password ')) {$query->where ($key, $value); }} return $query->first (); Verify user Public Function Validatecredentials (usercontract $user, array $credentials) {$pla by given user authentication data.}// in = $credentials [' Password ']; return $this->hasher->check ($plain, $user->getauthpassword ()); }}class Bcrypthasher implements hashercontract{//calculates the hash value of a given value by using the Bcrypt algorithm public function make ($value, array $option s = []) {$hash = Password_hash ($value, Password_bcrypt, [ ' Cost ' = $this->cost ($options),]); if ($hash = = = False) {throw new RuntimeException (' Bcrypt hashing not supported. '); } return $hash; }//Verifies whether the hash value is given a clear text value computed by the Bcrypt algorithm public function check ($value, $hashedValue, array $options = []) {if (strlen ($hashedValue) = = = 0) {return false; } return Password_verify ($value, $hashedValue); }}
The authentication of the user's password is EloquentUserProvider
done by relying on the hasher
Hashiller, and the Laravel authentication system uses the BCRYPT algorithm to encrypt the user-supplied plaintext password and store it in the user's table by default, and the haser
Hashiller method is validated by the check
PHP built-in method. password_verify
to verify that the plaintext password is the original value of the stored ciphertext password.
The main details of the user authentication system we know how to define our own gatekeeper (guard) or user provider (Userprovider), and first they must implement the methods in their respective contracts to seamlessly access the Laravel auth system, Then also need to be defined by the guard or provider through Auth::extend
, Auth::provider
method registration return to guard or provider instance of the closure to Laravel, guard and Userprovider custom is not must set, We can customize the guard by itself still using the default Eloquentuserprovider, or let the default Sessionguard use the custom Userprovider.
In the next section I will give a case that we used in our previous project development to better explain how the Laravel auth system should be extended.
The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!