当前位置:首页 > CMS教程 > 其它CMS > 列表

laravel修改用户模块的密码验证实现

发布:smiling 来源: PHP粉丝网  添加日期:2022-05-15 11:52:52 浏览: 评论:0 

本文主要介绍了laravel修改用户模块的密码验证实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。

做项目的时候,用户认证几乎是必不可少的,如果我们的项目由于一些原因不得不使用 users 之外的用户表进行认证,那么就需要多做一点工作来完成这个功能。

现在假设我们只需要修改登录用户的表,表名和表结构都与框架默认的表users不同,文档没有教我们如何去做,但是别慌,稍微看下框架实现用户认证的源码就能轻松实现。

首先,自定义一张表用来登录,表结构和模拟数据如下:

表 admins

id login_name login_pass

1 admin 2y10$2MUhp7b6ghVOngb/.b/x6uuEW/yL3FqPKJztawrM0U577Clf07xda

从配置文件入手

用户认证相关的配置都保存在config/auth.php文件中,先来看看配置文件的内容:

  1. <?php 
  2.   
  3. return [ 
  4.   
  5.     /* 
  6.     |-------------------------------------------------------------------------- 
  7.     | Authentication Defaults 
  8.     |-------------------------------------------------------------------------- 
  9.     | 
  10.     | This option controls the default authentication "guard" and password 
  11.     | reset options for your application. You may change these defaults 
  12.     | as required, but they're a perfect start for most applications. 
  13.     | 
  14.     */ 
  15.   
  16.     'defaults' => [ 
  17.         'guard' => 'web'
  18.         'passwords' => 'users'
  19.     ], 
  20.   
  21.     /* 
  22. |-------------------------------------------------------------------------- 
  23. | Authentication Guards 
  24. |-------------------------------------------------------------------------- 
  25. | 
  26. | Next, you may define every authentication guard for your application. 
  27. | Of course, a great default configuration has been defined for you 
  28. | here which uses session storage and the Eloquent user provider. 
  29. | 
  30. | All authentication drivers have a user provider. This defines how the 
  31. | users are actually retrieved out of your database or other storage 
  32. | mechanisms used by this application to persist your user's data. 
  33. | 
  34. | Supported: "session", "token" 
  35. | 
  36. */ 
  37.  
  38. 'guards' => [ 
  39.     'web' => [ 
  40.         'driver' => 'session'
  41.         'provider' => 'users'
  42.     ], 
  43.  
  44.     'api' => [ 
  45.         'driver' => 'passport'
  46.         'provider' => 'users'
  47.     ], 
  48. ], 
  49.  
  50. /* 
  51. |-------------------------------------------------------------------------- 
  52. | User Providers 
  53. |-------------------------------------------------------------------------- 
  54. | 
  55. | All authentication drivers have a user provider. This defines how the 
  56. | users are actually retrieved out of your database or other storage 
  57. | mechanisms used by this application to persist your user's data. 
  58. | 
  59. | If you have multiple user tables or models you may configure multiple 
  60. | sources which represent each model / table. These sources may then 
  61. | be assigned to any extra authentication guards you have defined. 
  62. | 
  63. | Supported: "database", "eloquent" 
  64. | 
  65. */ 
  66.  
  67. 'providers' => [ 
  68.     'users' => [ 
  69.         'driver' => 'eloquent'
  70.         'model' => App\User::class
  71.     ], 
  72.  
  73.     // 'users' => [ 
  74.     //     'driver' => 'database', 
  75.     //     'table' => 'users', 
  76.     // ], 
  77. ], 
  78.  
  79. /* 
  80. |-------------------------------------------------------------------------- 
  81. | Resetting Passwords 
  82. |-------------------------------------------------------------------------- 
  83. | 
  84. | You may specify multiple password reset configurations if you have more 
  85. | than one user table or model in the application and you want to have 
  86. | separate password reset settings based on the specific user types. 
  87. | 
  88. | The expire time is the number of minutes that the reset token should be 
  89. | considered valid. This security feature keeps tokens short-lived so 
  90. | they have less time to be guessed. You may change this as needed. 
  91. | 
  92. */ 
  93.  
  94. 'passwords' => [ 
  95.     'users' => [ 
  96.         'provider' => 'users'
  97.         'table' => 'password_resets'
  98.         'expire' => 60, 
  99.     ], 
  100. ], 

默认使用的守卫是web,而web守卫使用的认证驱动是session,用户提供器是users。假设我们的需求只是将用户的提供器由users改为admins,那么我们需要做两步操作:

修改默认的用户提供器,将provider=>'users'改为provider=>'admins'

  1. 'guards' => [ 
  2.       'web' => [ 
  3.           'driver' => 'session'
  4.           'provider' => 'users'
  5.       ], 
  6.   ], 

配置admins提供器,假设依旧使用eloquent作为驱动,并创建好了admins表的模型

  1. 'providers' => [ 
  2.         'admins' => [ 
  3.             'driver' => 'eloquent'
  4.             'model' => App\Admin::class 
  5.         ] 
  6.     ], 

使用Auth门面的attempt方法进行登录

SessionGuard 中的attempt方法:

  1. //Illuminate\Auth\SessionGuard 
  2.  public function attempt(array $credentials = [], $remember = false) 
  3.     { 
  4.         $this->fireAttemptEvent($credentials$remember); 
  5.  
  6.         $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); 
  7.  
  8.         // If an implementation of UserInterface was returned, we'll ask the provider 
  9.         // to validate the user against the given credentials, and if they are in 
  10.         // fact valid we'll log the users into the application and return true. 
  11.         if ($this->hasValidCredentials($user$credentials)) { 
  12.             $this->login($user$remember); 
  13.  
  14.             return true; 
  15.         } 
  16.  
  17.         // If the authentication attempt fails we will fire an event so that the user 
  18.         // may be notified of any suspicious attempts to access their account from 
  19.         // an unrecognized user. A developer may listen to this event as needed. 
  20.         $this->fireFailedEvent($user$credentials); 
  21.  
  22.         return false; 
  23.     } 

该方法中调用 UserProvider 接口的retrieveByCredentials方法检索用户,根据我们的配置,UserProvider接口的具体实现应该是EloquentUserProvider,因此,我们定位到EloquentUserProvider的retrieveByCredentials方法:

  1. //Illuminate\Auth\EloquentUserProvider 
  2. public function retrieveByCredentials(array $credentials
  3.     { 
  4.         if (emptyempty($credentials) || 
  5.            (count($credentials) === 1 && 
  6.             array_key_exists('password'$credentials))) { 
  7.             return
  8.         } 
  9.  
  10.         // First we will add each credential element to the query as a where clause. 
  11.         // Then we can execute the query and, if we found a user, return it in a 
  12.         // Eloquent User "model" that will be utilized by the Guard instances. 
  13.         $query = $this->createModel()->newQuery(); 
  14.  
  15.         foreach ($credentials as $key => $value) { 
  16.             if (Str::contains($key'password')) { 
  17.                 continue
  18.             } 
  19.  
  20.             if (is_array($value) || $value instanceof Arrayable) { 
  21.                 $query->whereIn($key$value); 
  22.             } else { 
  23.                 $query->where($key$value); 
  24.             } 
  25.         } 
  26.  
  27.         return $query->first(); 
  28.     } 

该方法会使用传入的参数(不包含password)到我们配置的数据表中搜索数据,查询到符合条件的数据之后返回对应的用户信息,然后attempt方法会进行密码校验,校验密码的方法为:

  1. //Illuminate\Auth\SessionGuard 
  2. /** 
  3.      * Determine if the user matches the credentials. 
  4.      * 
  5.      * @param  mixed  $user 
  6.      * @param  array  $credentials 
  7.      * @return bool 
  8.      */ 
  9.     protected function hasValidCredentials($user$credentials
  10.     { 
  11.         return ! is_null($user) && $this->provider->validateCredentials($user$credentials); 
  12.     } 

进一步查看EloquentUserProvider中的validateCredentials方法

  1. //Illuminate\Auth\EloquentUserProvider 
  2. public function validateCredentials(UserContract $userarray $credentials
  3.     $plain = $credentials['password']; 
  4.  
  5.     return $this->hasher->check($plain$user->getAuthPassword()); 

通过validateCredentials可以看出,提交的认证数据中密码字段名必须是password,这个无法自定义。同时可以看到,入参$user必须实现Illuminate\Contracts\Auth\Authenticatable接口(UserContract是别名)。

修改 Admin 模型

Admin模型必须实现Illuminate\Contracts\Auth\Authenticatable接口,可以借鉴一下User模型,让Admin直接继承Illuminate\Foundation\Auth\User 就可以,然后重写getAuthPassword方法,正确获取密码字段:

  1. // App\Admin 
  2. public function getAuthPassword() 
  3.     return $this->login_pass; 

不出意外的话,这个时候就能使用admins表进行登录了。

Larval 5.4的默认Auth登陆传入邮件和用户密码到attempt 方法来认证,通过email 的值获取,如果用户被找到,经哈希运算后存储在数据中的password将会和传递过来的经哈希运算处理的passwrod值进行比较。如果两个经哈希运算的密码相匹配那么将会为这个用户开启一个认证Session。

参考上面的分析,我们就需要对EloquentUserProvider中的validateCredentials方法进行重写,步骤如下。

1. 修改 App\Models\User.php 添加如下代码:

  1. public function getAuthPassword() 
  2.     { 
  3.         return ['password' => $this->attributes['password'], 'salt' => $this->attributes['salt']]; 
  4.     } 

2. 建立一个自己的UserProvider.php 的实现

  1. <?php  
  2. namespace App\Foundation\Auth; 
  3.   
  4. use Illuminate\Auth\EloquentUserProvider; 
  5. use Illuminate\Contracts\Auth\Authenticatable; 
  6. use Illuminate\Support\Str; 
  7.   
  8. /** 
  9.  * 重写用户密码校验逻辑 
  10.  * Class GfzxEloquentUserProvider 
  11.  * @package App\Foundation\Auth 
  12.  */ 
  13. class GfzxEloquentUserProvider extends EloquentUserProvider 
  14.     /** 
  15.      * Validate a user against the given credentials. 
  16.      * 
  17.      * @param  \Illuminate\Contracts\Auth\Authenticatable $user 
  18.      * @param  array $credentials 
  19.      * @return bool 
  20.      */ 
  21.     public function validateCredentials(Authenticatable $userarray $credentials
  22.     { 
  23.         $plain = $credentials['password']; 
  24.         $authPassword = $user->getAuthPassword(); 
  25.         return md5($plain . $authPassword['salt']) == $authPassword['password']; 
  26.     } 

3. 将User Providers换成我们自己的GfzxEloquentUserProvider

修改 app/Providers/AuthServiceProvider.php

  1. <?php 
  2.  
  3. namespace App\Providers; 
  4.  
  5. use App\Foundation\Auth\GfzxEloquentUserProvider; 
  6. use Auth; 
  7. use Illuminate\Support\Facades\Gate; 
  8. use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; 
  9.  
  10. class AuthServiceProvider extends ServiceProvider 
  11.     . 
  12.     . 
  13.     . 
  14.  
  15.     /** 
  16.      * Register any authentication / authorization services. 
  17.      * 
  18.      * @return void 
  19.      */ 
  20.     public function boot() 
  21.     { 
  22.         $this->registerPolicies(); 
  23.  
  24.         Auth::provider('gfzx-eloquent'function ($app$config) { 
  25.             return new GfzxEloquentUserProvider($this->app['hash'], $config['model']); 
  26.         }); 
  27.     } 

4. 修改 config/auth.php

  1. 'providers' => [ 
  2.      'users' => [ 
  3.          'driver' => 'gfzx-eloquent'
  4.          'model' => App\Models\User::class
  5.      ], 
  6.  ], 

这是就可以用过salt+passwrod的方式密码认证了。

Tags: laravel修改用户模块

分享到: