Certified user details by modifying Laravel auth using salt and password

Source: Internet
Author: User
Tags sha1 traits
This article mainly introduces to you by modifying Laravel auth to use salt and password to authenticate users of the relevant information, the text through the sample code introduced in very detailed, to everyone's study or work has a certain reference learning value, need to see the friends below.

Objective

This article mainly introduces to you by modifying the Laravel auth with salt and password to authenticate the user's relevant content, share out for everyone to reference the study, the following words do not say, come together to see the detailed introduction:

Laraval user authentication system Auth is very powerful and easy to use, but in Laravel user authentication system, user registration, login, retrieve password in these modules using the password encryption and authentication algorithm used is bcrypt, and many of the previous Project user table is to use a storage salt + Password encrypt the string to record the user's password, which gives the use of the Laravel framework to reconstruct the project before the great resistance, but recently himself through the Internet to find information, see community forums, see the source and other ways to complete the laravel auth modification, Share it here and hope it will help others. Before you get to the beginning, you need to explain that if you apply the Laravel framework to a new project, you do not need to make any modifications to auth, and the default Bcrypt encryption algorithm is more secure and efficient than the SALT + password encryption algorithm.

Modify User Registration

First, the artisan command to enable authentication in Laravel


PHP Artisan Make:auth

One more static method call in the routes file (location: app/http/routes.php) after executing the command


Route::auth ();

This Route is a facade (located in Illuminate\support\facades\route) of Laravel, and the Auth method called is defined in the Illuminate\routing\router class, As you can see in the Auth method, you define some auth-related routing rules.


/** * Register The typical authentication routes for an application. * * @return void */public function auth () {//Authentication Routes ... $this->get (' login ', ' Auth\authcontroller@showlo Ginform '); $this->post (' login ', ' auth\authcontroller@login '); $this->get (' logout ', ' auth\authcontroller@logout '); Registration Routes $this->get (' register ', ' Auth\authcontroller@showregistrationform '); $this->post (' register ', ' Auth\authcontroller@register '); Password Reset Routes ... $this->get (' Password/reset/{token?} ', ' auth\passwordcontroller@showresetform '); $this->post (' Password/email ', ' auth\passwordcontroller@sendresetlinkemail '); $this->post (' Password/reset ', ' Auth\passwordcontroller@reset ');}

By routing rules you can see that the Controller method requested at registration is the Authcontroller register method, which is defined in the \illuminate\foundation\auth\registersusers traits, Authcontroller introduced this traits in the class definition.


/** * Handle A registration request for the application. * * @param \illuminate\http\request $request * @return \illuminate\http\response */public function Register (Request $requ EST) {$validator = $this->validator ($request->all ()); if ($validator->fails ()) {$this Throwvalidationexception (  $request, $validator);} Auth::guard ($this->getguard ())->login ($this->create ($request->all ())); Return Redirect ($this->redirectpath ());}

The Register method first validates the user input data in the request, and you only need to define your own validation rules for each input field in the Authcontroller validator method.


Protected function Validator (array $data) {return Validator::make ($data, [' name ' = ' required|max:255 ', ' email ' = ' Required|email|max:255|unique:user ', ' password ' = ' required|size:40|confirmed ',]);}

Then after the verification pass, Laravel will drop the Authcontroller create method to generate a new user, and then take the new user's data to log inAuth::guard($this->getGuard())->login($this->create($request->all()));

So we're going to customize the encryption method of generating user password when user registers only need to modify Authcontroller's Create method.

Like what:


/** * Create A new user instance after a valid registration. * * @param array $data * @return User */protected function Create (array $data) {$salt = Str::random (6); return user::creat E ([' Nickname ' = $data [' name '], ' email ' + $data [' email '], ' password ' = SHA1 ($salt. $data [' Password ']), ' Regis Ter_time ' + Time (), ' register_ip ' = Ip2long (Request ()->ip ()), ' salt ' = $salt]);

Modify User Login

Before modifying the login we need to see the specific controller and method of the login request through the routing rules, which can be seen in the Auth method definition mentioned above.


$this->get (' login ', ' auth\authcontroller@showloginform '); $this->post (' login ', ' auth\authcontroller@login '); $this->get (' logout ', ' auth\authcontroller@logout ');

Verify that the login operation is in the login method of the \app\http\controllers\auth\authcontroller class. Open Authcontroller found Auth related methods are introduced into the class through the traits (traits), in the class use to introduce the traits, at compile time PHP will copy the traits code into the class, This is the specific application scenario and use of the features introduced by PHP5.5 is not detailed here. The 以AuthController@login method is actually defined in the
\illuminate\foundation\auth\authenticatesusers in this traits.


/** * Handle a login request to the application. * * @param \illuminate\http\request $request * @return \illuminate\http\response */public function Login (Request $request) {$this->validatelogin ($ request); $throttles = $this->isusingthrottlesloginstrait (); if ($throttles && $lockedOut = $this->hastoomanyloginattempts ($request)) {$this->firelockoutevent ($ request); return $this->sendlockoutresponse ($request); } $credentials = $this->getcredentials ($request); if (Auth::guard ($this->getguard ())->attempt ($credentials, $request->has (' remember ')) {return $this- Handleuserwasauthenticated ($request, $throttles); if ($throttles &&! $lockedOut) {$this->incrementloginattempts ($request);} return $this Sendfailedloginresponse ($request);} 

The main operation of login verification is Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember')); done in this method call, Auth::guard($this->getGuard()) get to the \illuminate\auth\sessionguard (how to get the see Auth this facade \illuminate\auth\ AuthManager in the source code)

Take a look at how the Sessionguard attempt method is implemented:


Public function attempt (array $credentials = [], $remember = False, $login = True) {$this->fireattemptevent ($credential S, $remember, $login); $this->lastattempted = $user = $this->provider->retrievebycredentials ($credentials); if ($this->hasvalidcredentials ($user, $credentials)) {if ($login) {  $this->login ($user, $remember);} return True if ($login) {$this->firefailedevent ($user, $credentials);} return false;} /** * Determine if the user matches the credentials. * * @param mixed $user * @param array $credentials * @return bool */protected function hasvalidcredentials ($user, $credent ials) {return! Is_null ($user) && $this->provider->validatecredentials ($user, $credentials);}

Retrievebycredentials is the actual process of extracting the user data from the database with the passed in field, and validatecredentials is used to verify that the password is correct.

It is important to note that $this->provider this provider is a provider that implements the \illuminate\contracts\auth\userprovider class, and we see the directory illuminate\ Auth below there are two implementations of Userprovider, respectively, Databaseuserprovider and Eloquentuserprovider, but we verify the password by that to verify, look at the auth configuration file


' Providers ' = [' users ' and ' = ' driver ' = ' eloquent ', ' model ' + app\user::class,//This is the model used for driver,],

The configuration here is driver => eloquent , then, through Eloquentuserprovider's retrievebycredentials to verify that this Eloquentuserprovider is injected in the Sessionguard instantiation, (specifically how to read the Auth configuration file, instantiate the corresponding provider injected into the Sessionguard, please refer to the \illuminate\auth\authmanager The source code of the Createsessiondriver method)

Next we continue to look at the implementation of the Retrievebycredentials and Validatecredentials methods in Eloquentuserprovider:


/** * Retrieve A user by the given credentials. * * @param array $credentials * @return \illuminate\contracts\auth\authenticatable|null */public function Retrievebycredentials (array $credentials) {if (empty ($credentials)) {return;} $query = $this->createmodel () NewQuery (); foreach ($credentials as $key = + $value) {if (! Str::contains ($key, ' password ')) {  $query->where ($key, $value);} return $query->first ();} /** * Validate A user against the given credentials. * * @param \illuminate\contracts\auth\authenticatable $user * @param array $credentials * @return bool */public function v Alidatecredentials (usercontract $user, array $credentials) {$plain = $credentials [' password ']; return $this Hasher->check ($plain, $user->getauthpassword ());}

The above two methods retrievebycredentials use a field other than the password to remove user records from the database user's table, such as using email to query the user records, and then Validatecredentials method is through $this->haser->check To compare the password entered and the hashed password to verify that the password is correct.

Well, see here is very obvious, we need to change to their own password verification is to implement a validatecredentials on their own, modify the $this->hasher->check for our own password validation rules can be.

First we modify the $user->getAuthPassword() salt and password of the user table in the database to Validatecredentials
Modify app\user.php Add the following code


/** * The table associated to this model */protected $table = ' user ';//The username is not a laravel convention here to specify


/** * Disable Laravel Auto-manage timestamp column */public $timestamps = false;/** * Overrides the default Laravel method in Getauthpassword, returning the user's password and salt fields * @ return type */public function Getauthpassword () {return [' password ' = ' $this->attributes[' password '], ' salt ' = $this->attributes[' salt '];}

We then set up an implementation of our own Userprovider interface and put it in a custom directory:

New app/foundation/auth/admineloquentuserprovider.php


namespace App\foundation\auth;use illuminate\auth\eloquentuserprovider;use illuminate\contracts\auth\ Authenticatable;use illuminate\support\str;class Admineloquentuserprovider extends eloquentuserprovider{/**  * Validate a user against the given credentials.  *  * @param \illuminate\contracts\auth\authenticatable $user  * @param array $credentials */public  function Validatecredentials (authenticatable $user, array $credentials) {  $plain = $credentials [' password '];  $authPassword = $user->getauthpassword ();  return SHA1 ($authPassword [' salt ']. $plain) = = $authPassword [' Password ']; }}

Finally, we modify the Auth configuration file to let Laravel use the provider we just defined when doing auth verification,
Modify config/auth.php:


' Providers ' = [' users ' and ' = '  driver ' = ' admin-eloquent '  , ' model ' + App\user::class,]]

Modify app/provider/authserviceprovider.php


Public Function boot (gatecontract $gate) {$this->registerpolicies ($gate); \auth::p rovider (' admin-eloquent '), function ($app, $config) {  return New \app\foundation\auth\admineloquentuserprovider ($app [' Hash '], $config [' Model ']); });}

Auth: The:p Rovider method is used to register the provider constructor, which is a closure,provider method of the specific code implemented in the AuthManager file


Public function provider ($name, Closure $callback) {$this->customprovidercreators[$name] = $callback; return $this;}

The closure returned the Admineloquentuserprovider object for Laravel auth use, OK, after these modifications Laravel auth in the user login verification is the use of custom salt + password way.

Modify Reset Password

The workflow for resetting passwords for Laravel is:

    • Send a message with the Reset password link to the mailbox of the user who needs to reset the password, and the link will contain the user's email address and token.

    • The user clicks on the link in the message to enter a new password on the Reset Password page, laravel the new password to the user's record in the data table by verifying that the user is the user who initiated the Reset password request after authenticating the email and token.

The first step is to configure the Laravel email feature, and also to create a new table in the database password_resets to store the user's email and corresponding tokens


CREATE TABLE ' password_resets ' (' email ' varchar (255) COLLATE utf8_unicode_ci not NULL, ' token ' varchar (255) COLLATE utf8_ Unicode_ci not NULL, ' created_at ' timestamp not NULL, key ' Password_resets_email_index ' (' email '), key ' password_resets_t Oken_index ' (' token ')) Engine=innodb DEFAULT Charset=utf8 collate=utf8_unicode_ci;

By resetting the submission address of the password form, you can see that the form submits the new password to the/password/reset by post, and we first look at the auth-related routes to determine the/password/reset corresponding controller method.


$this->post (' Password/reset ', ' auth\passwordcontroller@reset ');

You can see that the corresponding controller method is the reset method of the \app\http\controllers\auth\passwordcontroller class, and this method is actually defined in the \illuminate\foundation\auth\ Resetspasswords This traits, Passwordcontroller introduced this traits


/** * Reset The given user ' s password. * * @param \illuminate\http\request $request * @return \illuminate\http\response */public function Reset (Request $request ) {$this->validate (  $request,  $this->getresetvalidationrules (),  $this- Getresetvalidationmessages (),  $this->getresetvalidationcustomattributes ()); $credentials = $this->getresetcredentials ($request); $broker = $this->getbroker (); $response = Password::broker ($broker)->reset ($credentials, function ($user, $password) {  $this ResetPassword ($user, $password); }); Switch ($response) {case  Password::P assword_reset:   return $this->getresetsuccessresponse ($response);  Default:   return $this->getresetfailureresponse ($request, $response);}}

The method first validates the input by validator, then passes the new password and a closure object to the Password::broker ($broker)->reset () in the program, which is defined in the \illuminate\ In the Auth\passwords\passwordbroker class.


/** * Reset the password for the given token. * * @param array $credentials * @param \closure $callback * @return mixed */public function reset (array $credentials, Closure $callback) {//If the responses fro M The Validate method is not a user instance, we'll//assume that it's a redirect and simply return it from this Metho D and//the user is properly redirected has a error message on the post. $user = $this->validatereset ($credentials); if (! $user instanceof canresetpasswordcontract) {return $user;} $pass = $credentials [' Password ']; Once We have called this callback, we'll remove this token row from the//table and return the response from this CA Llback so the user gets sent//to the destination given by the developers from the callback return. Call_user_func ($callback, $user, $pass); $this->tokens->delete ($credentials [' token ']); return static::P Assword_reset;} 

In the Passwordbroker reset method, the program will first authenticate the user's submitted data, then pass the password and user instance to the closed packet, and complete the operation of updating the new password to the user table in the closure call. The ResetPassword method of the Passwrodcontroller class that the program called in the closure


function ($user, $password) {$this->resetpassword ($user, $password);});

Definition of Passwrodcontroller class ResetPassword method


protected function ResetPassword ($user, $password) {$user->forcefill ([  ' Password ' = bcrypt ($password),  ' Remember_token ' = Str::random (60),]) ->save (); Auth::guard ($this->getguard ())->login ($user);}

In this method laravel use is bcrypt encrypted password, then to change to We need salt + password way, We can override this method in the Passwordcontroller class by overriding the ResetPassword method in the traits.


/** * Overwrite the ResetPassword method in Resetspasswords traits, instead of using SHA1 (salt + Password) encryption method * Reset The given user's password.  * * @param \illuminate\contracts\auth\canresetpassword $user * @param string $password * @return void */protected function ResetPassword ($user, $password) {$salt = Str::random (6); $user->forcefill ([  ' password ' = = SHA1 ($salt. $ password),  ' salt ' and ' $salt,  ' remember_token ' = str::random (UP),])->save (); \auth::guard ($this->getguard ())->login ($user);}

Conclusion

The custom of Laravel Auth is completed, and the registration, login and reset password are changed to SHA1 (salt + password) password encryption method. All custom code is done by defining the subclasses of the Laravel related classes and overriding methods to complete the source code without modifying the Laravel, thus maintaining good scalability and ensuring that the project is free to migrate.

Note: The laravel version used is 5.2

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.