Laravel5.2Auth authentication resolution and use salt + passwrod encryption to verify Larval 5.2's default Auth login incoming mail and user password to the attempt method for authentication, obtained through the e-mail value, if the user is found, after the hash operation, the password stored in the data will be compared with the pass-in passwrod value processed by the hash operation. If two passwords matched by the hash operation, an authentication Session is enabled for this user.
However, passwords in some of our systems are often authenticated by using salt + password, or some old systems are authenticated by salt + passwrod, now, how can I use the salt + password method for password authentication instead of the default passwrod method?
To solve the problem, we 'd better understand the root cause first.
First, let's take a look at how Laravel performs password verification by default, and see what the Auth: guard ($ this-> getGuard ()-> attempt ($ credentials) method has done:
Illuminate/Contracts/Auth/StatefulGuard. php
namespace Illuminate\Contracts\Auth;interface StatefulGuard extends Guard { /** * Attempt to authenticate a user using the given credentials. * * @param array $credentials * @param bool $remember * @param bool $login * @return bool */ public function attempt(array $credentials = [], $remember = false, $login = true); ......
The code above shows that attempt is the method in the StatefulGuard interface, the first parameter is the field to be authenticated, the second parameter is whether to remember to log on, and the third parameter is logged on, continue to see how attempt is implemented in SessionGuard.
Illuminate/auth/SessionGuard. php
class SessionGuard implements StatefulGuard, SupportsBasicAuth { use GuardHelpers; ...... /** * Attempt to authenticate a user using the given credentials. * * @param array $credentials * @param bool $remember * @param bool $login * @return bool */ public function attempt(array $credentials = [], $remember = false, $login = true) { $this->fireAttemptEvent($credentials, $remember, $login); $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); if ($this->hasValidCredentials($user, $credentials)) { if ($login) { $this->login($user, $remember); } return true; } return false; } /** * Determine if the user matches the credentials. * * @param mixed $user * @param array $credentials * @return bool */ protected function hasValidCredentials($user, $credentials) { return ! is_null($user) && $this->provider->validateCredentials($user, $credentials); }.......}
You can see that the verification is implemented through $ this-> provider-> retrieveByCredentials ($ credentials); and $ this-> provider-> validateCredentials ($ user, $ credentials, retrieveByCredentials is used to verify the existence of user records in the passed fields. validateCredentials is the actual verification process through the password and the passed password in the user records.
Note that $ this-> provider is actually the provider that implements Illuminate \ Contracts \ Auth \ UserProvider, we can see that there are two UserProvider implementations under Illuminate/Contracts/Auth, respectively DatabaseUserProvider. php and EloquentUserProvider. php. But when we verify the password, which one is used to verify the password?
Config/auth. php
'Providers '=> ['users' => ['Drivers' => 'eloquent', 'model' => App \ Models \ User: class, // This is the User Model],],
Here I have configured the 'driver '=> 'eloquent', which is verified by retrieveByCredentials in EloquentUserProvider. php. let's continue to see what it has done.
Illuminate/auth/EloquentUserProvider. php
class EloquentUserProvider implements UserProvider {...... /** * Retrieve a user by the given credentials. * * @param array $credentials * @return \Illuminate\Contracts\Auth\Authenticatable|null */ public function retrieveByCredentials(array $credentials) { // First we will add each credential element to the query as a where clause. // Then we can execute the query and, if we found a user, return it in a // Eloquent User "model" that will be utilized by the Guard instances. $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 validateCredentials(UserContract $user, array $credentials) { $plain = $credentials['password']; return $this->hasher->check($plain, $user->getAuthPassword()); } ......}
The preceding two methods retrieveByCredentials use a verification field other than the password to check whether the record exists. for example, you can use an email to check whether the user record exists, then, the validateCredentials method compares the entered password with the hash password through $ this-> hasher-> check to verify that the password is correct. $ plain is the string submitted for the encrypted password, $ user-> getAuthPassword () is the encrypted password string stored in database records.
Well, we can see that it is obvious here. we need to change it to our own password for verification. isn't it enough to implement the validateCredentials method on our own, change $ this-> hasher-> check to verify the password. let's get started!
- First, implement $ user-> getAuthPassword (); pass the salt and password of the user table in the database to validateCredentials:
Modify App \ Models \ User. php and add the following code:
public function getAuthPassword() { return ['password' => $this->attributes['password'], 'salt' => $this->attributes['salt']]; }
- Then we will create our own UserProvider. php implementation. you can put it anywhere, and I will put it in the custom directory:
Create app/Foundation/Auth/RyanEloquentUserProvider. php
getAuthPassword(); return sha1($authPassword['salt'] . sha1($authPassword['salt'] . sha1($plain))) == $authPassword['password']; }
Here, I pass the salt and password recorded by the user through $ user-> getAuthPassword ();, and then encrypt the passwords $ plain and salt submitted for authentication, if the encryption result matches the password string recorded in the user database, the authentication is successful. of course, the encryption algorithm is completely customized.
- Finally, we replace User Providers with our own RyanEloquentUserProvider.
Modify app/Providers/AuthServiceProvider. php
public function boot(GateContract $gate) { $this->registerPolicies($gate); \Auth::provider('ryan-eloquent', function ($app, $config) { return new RyanEloquentUserProvider($this->app['hash'], $config['model']); }); }
Modify config/auth. php
'providers' => [ 'users' => [ 'driver' => 'ryan-eloquent', 'model' => App\Models\User::class, ], ],
Okay, try again and use the password authentication method salt + passwrod!
Reprinted please note: Reprinted from Ryan is a Cainiao | LNMP technology stack notes
If you think this article is very helpful to you, why not give it a try?