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

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

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

表 admins

id login_name login_pass
1 admin $2y$10$2MUhp7b6ghVOngb/.b/x6uuEW/yL3FqPKJztawrM0U577Clf07xda

从配置文件入手

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

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

默认使用的守卫是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. $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
  6. // If an implementation of UserInterface was returned, we'll ask the provider
  7. // to validate the user against the given credentials, and if they are in
  8. // fact valid we'll log the users into the application and return true.
  9. if ($this->hasValidCredentials($user, $credentials)) {
  10. $this->login($user, $remember);
  11. return true;
  12. }
  13. // If the authentication attempt fails we will fire an event so that the user
  14. // may be notified of any suspicious attempts to access their account from
  15. // an unrecognized user. A developer may listen to this event as needed.
  16. $this->fireFailedEvent($user, $credentials);
  17. return false;
  18. }

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

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

该方法会使用传入的参数(不包含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 $user, array $credentials)
  3. {
  4. $plain = $credentials['password'];
  5. return $this->hasher->check($plain, $user->getAuthPassword());
  6. }

通过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. {
  4. return $this->login_pass;
  5. }

不出意外的话,这个时候就能使用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. use Illuminate\Auth\EloquentUserProvider;
  4. use Illuminate\Contracts\Auth\Authenticatable;
  5. use Illuminate\Support\Str;
  6. /**
  7. * 重写用户密码校验逻辑
  8. * Class GfzxEloquentUserProvider
  9. * @package App\Foundation\Auth
  10. */
  11. class GfzxEloquentUserProvider extends EloquentUserProvider
  12. {
  13. /**
  14. * Validate a user against the given credentials.
  15. *
  16. * @param \Illuminate\Contracts\Auth\Authenticatable $user
  17. * @param array $credentials
  18. * @return bool
  19. */
  20. public function validateCredentials(Authenticatable $user, array $credentials)
  21. {
  22. $plain = $credentials['password'];
  23. $authPassword = $user->getAuthPassword();
  24. return md5($plain . $authPassword['salt']) == $authPassword['password'];
  25. }
  26. }

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

修改 app/Providers/AuthServiceProvider.php

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

4. 修改 config/auth.php

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

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

文章参考

laravel 修改用户模块密码验证

Laravel 中自定义用户登录的数据表

laravel修改用户模块的密码验证的更多相关文章

  1. linux 用户管理修改用户信息、密码状态、删除用户、退出登陆、切换用户

    修改用户信息usermoduseradd支持的选项usermod都支持passwd有两个选项-l(在密码串前面加了两个叹号),-u,usermod有两个选项:-L 临时锁定用户(Lock)(在密码串前 ...

  2. Ubuntu修改用户和root密码

    如果要修改root的密码:sudo passwd 如果要修改_当前_用户的密码:passwd 如果要修改其他用户的密码(你得有权限):sudo passwd USERNAME,USERNAME就是你要 ...

  3. laravel 修改时邮箱字段唯一性验证时忽略指定 ID

  4. MySQL8 修改密码验证插件

    MySQL8 修改密码验证插件 查看当前用户使用的密码验证插件 mysql> show variables like '%auth%'; +--------------------------- ...

  5. linux中用户信息及密码相关知识

    在linux中若修改用户信息.密码,组群信息.密码等.其实是在修改/etc/passwd,/etc/shadow,/etc/group,/etc/groupshadow等文件的内容. 这四个文件的意思 ...

  6. pure-ftp 修改用户信息

    1.修改用户test的密码 [root@localhost bin]# ./pure-pw passwd test #修改密码 Password: Enter it again: [root@loca ...

  7. Linux基础命令---修改用户密码

    passwd 更改用户密码,超级用户可以修改所有用户密码,普通用户只能修改自己的密码.这个任务是通过调用LinuxPAM和LibuserAPI来完成的.本质上,它使用LinuxPAM将自己初始化为一个 ...

  8. 2015年末分享:利用RS修改用户密码

    马上就要2016农历新年了,送点什么给大家呢?我觉得还是分享点技术吧.前不久用户在抱怨为什么登录Cognos Connection的密码不能让我们自己改?相信Cognos开发的很多人知道,Cognos ...

  9. 从零开始实现asp.net MVC4框架网站的用户登录以及权限验证模块 详细教程

    从零开始实现asp.net MVC4框架网站的用户登录以及权限验证模块 详细教程   用户登录与权限验证是网站不可缺少的一部分功能,asp.net MVC4框架内置了用于实现该功能的类库,只需要简单搭 ...

随机推荐

  1. getch和getchar的区别

    造冰箱的大熊猫@cnblogs 2018/11/30 1.getc() 头文件:stdio.h 函数声明:int getc ( FILE * stream ); 功能: - 返回流(stream)当前 ...

  2. CentOS查看和修改PATH环境变量的方法

    查看PATH:echo $PATH以添加mongodb server为列修改方法一:export PATH=/usr/local/mongodb/bin:$PATH//配置完后可以通过echo $PA ...

  3. Linux命令-文件管理(一)

    Linux命令-文件管理(一) 1.命令:cat cat命令用于把档案串连接后传到基本输出(萤幕或加 > fileName 到另一个档案) 使用权限:所有使用者 语法格式:cat [-AbeEn ...

  4. C++入门经典-例5.3例5.4-输出int指针运算后的地址值

    1:代码如下: // 5.3.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...

  5. Django中csrf token验证原理

    我多年没维护的博客园,有一篇初学Django时的笔记,记录了关于django-csrftoekn使用笔记,当时几乎是照抄官网的使用示例,后来工作全是用的flask.博客园也没有维护.直到我的博客收到了 ...

  6. 【flask】使用类组织配置-使用工厂函数创建程序实例

    [需求] 使用配置类管理flask管理测试环境, 通过1个参数即可控制Flask是运行develpment环境还是production环境(数据库配置,邮件配置也要根据环境的变化而变化) [思路] 1 ...

  7. Windows下C/C++内存泄露检测机制

    1.概述 在Windows下微软给我们提供了一个十分强大的C/C++运行时库,这个运行时库中包含了很多有用的功能.而众多强大功能之一就是内存泄露的检测. C/C++提供了强大的内存管理功能,不过随之而 ...

  8. Kettle使用教程之Job使用

    1.Kettle的Job使用十分简单,这里也只是演示比较简单的操作,创建Job 2.点击转换,然后点击浏览,选择转换对象 3.执行按钮,运行该转换 4.如果需要长期的进行定时转换,可以在Job中的st ...

  9. JavaWeb实现文件上传下载功能实例解析 (好用)

    转: JavaWeb实现文件上传下载功能实例解析 转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web ...

  10. Dart学习笔记-运算符-条件表达式-类型转换

    Dart学习笔记-运算符-条件表达式-类型转换 一.运算符 1.算术运算符 + (加)- (减)* (乘)/ (除)~/ (取整) %(取余) 2.关系运算符 == (等等) != (不等) > ...