


Detailed explanation of user authentication by modifying Laravel Auth to use salt and password
This article mainly introduces you to the relevant information about using salt and password to authenticate users by modifying Laravel Auth. The article introduces it in detail through the example code. It has certain reference learning value for everyone's study or work. It is needed Friends, let’s take a look below.
Preface
This article mainly introduces you to the relevant content of using salt and password to authenticate users by modifying Laravel Auth. Share It’s out for everyone’s reference and study. I won’t say much below. Let’s take a look at the detailed introduction:
Laraval’s own user authentication system Auth is very powerful and easy to use. However, user registration in Laravel’s user authentication system Password encryption and authentication algorithms used in modules such as , login, and password retrieval all use bcrypt, and many previous projects use the method of storing salt + password encrypted strings to record user passwords in the user table. , which has brought great resistance to using the Laravel framework to reconstruct previous projects. However, I have recently completed the modification of Laravel Auth by searching for information on the Internet, reading community forums, and looking at the source code. I will share it here. Hope it helps others. Before I begin, I need to explain that if the Laravel framework is used in a new project, there is no need to make any modifications to Auth. The default bcrypt encryption algorithm is a more secure and efficient encryption algorithm than salt + password.
Modify user registration
First, enable verification in laravel using the artisan command
php artisan make:auth
After executing the command, there will be an additional static method call in the routes file (location: app/Http/routes.php)
Route::auth();
This Route It is a Facade of Laravel (located in Illuminate\Support\Facades\Route). The called auth method is defined in the Illuminate\Routing\Router class. As you can see below, the auth method defines 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@showLoginForm'); $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'); }
Through the routing rules, you can see that the controller method requested during registration is the register method of AuthController. This method is defined in the traits \Illuminate\Foundation\Auth\RegistersUsers. AuthController is in the class This trait is introduced in the definition.
/** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function register(Request $request) { $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()); }
In the register method, the user input data in the request will first be verified. You only need to define yourself in the validator method of AuthController. The verification rules for each input field can be
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 look down. After the verification is passed, Laravel will use the create method of AuthController to generate a new user, and then hold Use the new user’s data to log inAuth::guard($this->getGuard())->login($this->create($request->all()));
So if we want to customize the encryption method for generating user passwords during user registration, we only need to modify the create method of AuthController.
For example:
/** * 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::create([ 'nickname' => $data['name'], 'email' => $data['email'], 'password' => sha1($salt . $data['password']), 'register_time' => time(), 'register_ip' => ip2long(request()->ip()), 'salt' => $salt ]); }
Modify user login
Before modifying the login, we need to first look at the specific controller and method of the login request through the routing rules. You can see it 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');
The operation of verifying login is in the login method of \App\Http\Controllers\Auth\AuthController class. Open AuthController and find that Auth-related methods are introduced into the class through traits. Use the traits to be introduced in the class. During compilation, PHP will copy the code in the traits into the class. This is PHP5.5. The specific applicable scenarios and uses of the introduced features will not be detailed here. So the AuthController@login
method is actually defined in the
\Illuminate\Foundation\Auth\AuthenticatesUsers 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); }
login verification The main operation is in the method call Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'));
Performed, Auth::guard($this->getGuard())
What is obtained is \Illuminate\Auth\SessionGuard (see the Auth Facade \Illuminate\Auth\AuthManager for details on how to obtain it) Source code)
Look at how the attempt method in SessionGuard is implemented:
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; } 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, $credentials) { return ! is_null($user) && $this->provider->validateCredentials($user, $credentials); }
retrieveByCredentials uses the fields passed in to retrieve user data from the database. validateCredentials is the actual process used to verify that the password is correct.
What needs to be noted here is$this->provider
This provider is a provider that implements the \Illuminate\Contracts\Auth\UserProvider class. We see that under the directory Illuminate\Auth there is There are two UserProvider implementations, namely DatabaseUserProvider and EloquentUserProvider, but when we verify the password, which one is used to verify it? Take a look at the auth configuration file
'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\User::class, //这个是driver用的Model ], ],
这里配置的是driver => eloquent
, 那么就是通过EloquentUserProvider的retrieveByCredentials来验证的, 这个EloquentUserProvider 是在SessionGuard实例化时被注入进来的, (具体是怎么通过读取auth配置文件, 实例化相应的provider注入到SessionGuard里的请查阅\Illuminate\Auth\AuthManager 里createSessionDriver方法的源代码)
接下来我们继续查看EloquentUserProvider中retrieveByCredentials和validateCredentials方法的实现:
/** * 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 validateCredentials(UserContract $user, array $credentials) { $plain = $credentials['password']; return $this->hasher->check($plain, $user->getAuthPassword()); }
上面两个方法retrieveByCredentials用除了密码以外的字段从数据库用户表里取出用户记录,比如用email查询出用户记录,然后validateCredentials方法就是通过$this->haser->check
来将输入的密码和哈希的密码进行比较来验证密码是否正确。
好了, 看到这里就很明显了, 我们需要改成自己的密码验证就是自己实现一下validateCredentials就可以了, 修改$this->hasher->check为我们自己的密码验证规则就可以了。
首先我们修改$user->getAuthPassword()
把数据库中用户表的salt和password传递到validateCredentials中
修改App\User.php 添加如下代码
/** * The table associated to this model */ protected $table = 'user';//用户表名不是laravel约定的这里要指定一下
/** * 禁用Laravel自动管理timestamp列 */ public $timestamps = false; /** * 覆盖Laravel中默认的getAuthPassword方法, 返回用户的password和salt字段 * @return type */ public function getAuthPassword() { return ['password' => $this->attributes['password'], 'salt' => $this->attributes['salt']]; }
然后我们在建立一个自己的UserProvider接口的实现,放到自定义的目录中:
新建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']; } }
最后我们修改auth配置文件让Laravel在做Auth验证时使用我们刚定义的Provider,
修改config/auth.php:
'providers' => [ 'users' => [ 'driver' => 'admin-eloquent', 'model' => App\User::class, ] ]
修改app/Provider/AuthServiceProvider.php
public function boot(GateContract $gate) { $this->registerPolicies($gate); \Auth::provider('admin-eloquent', function ($app, $config) { return New \App\Foundation\Auth\AdminEloquentUserProvider($app['hash'], $config['model']); }); }
Auth::provider方法是用来注册Provider构造器的,这个构造器是一个Closure,provider方法的具体代码实现在AuthManager文件里
public function provider($name, Closure $callback) { $this->customProviderCreators[$name] = $callback; return $this; }
闭包返回了AdminEloquentUserProvider对象供Laravel Auth使用,好了做完这些修改后Laravel的Auth在做用户登录验证的时候采用的就是自定义的salt + password的方式了。
修改重置密码
Laravel 的重置密码的工作流程是:
向需要重置密码的用户的邮箱发送一封带有重置密码链接的邮件,链接中会包含用户的email地址和token。
用户点击邮件中的链接在重置密码页面输入新的密码,Laravel通过验证email和token确认用户就是发起重置密码请求的用户后将新密码更新到用户在数据表的记录里。
第一步需要配置Laravel的email功能,此外还需要在数据库中创建一个新表password_resets来存储用户的email和对应的token
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_token_index` (`token`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
通过重置密码表单的提交地址可以看到,表单把新的密码用post提交给了/password/reset,我们先来看一下auth相关的路由,确定/password/reset对应的控制器方法。
$this->post('password/reset', 'Auth\PasswordController@reset');
可以看到对应的控制器方法是\App\Http\Controllers\Auth\PasswordController类的reset方法,这个方法实际是定义在\Illuminate\Foundation\Auth\ResetsPasswords 这个traits里,PasswordController引入了这个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::PASSWORD_RESET: return $this->getResetSuccessResponse($response); default: return $this->getResetFailureResponse($request, $response); } }
方法开头先通过validator对输入进行验证,接下来在程序里传递把新密码和一个闭包对象传递给Password::broker($broker)->reset();方法,这个方法定义在\Illuminate\Auth\Passwords\PasswordBroker类里.
/** * 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 from the validate method is not a user instance, we will // assume that it is a redirect and simply return it from this method and // the user is properly redirected having an 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 will remove this token row from the // table and return the response from this callback 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::PASSWORD_RESET; }
在PasswordBroker的reset方法里,程序会先对用户提交的数据做再一次的认证,然后把密码和用户实例传递给传递进来的闭包,在闭包调用里完成了将新密码更新到用户表的操作, 在闭包里程序调用了的PasswrodController类的resetPassword方法
function ($user, $password) { $this->resetPassword($user, $password); });
PasswrodController类resetPassword方法的定义
protected function resetPassword($user, $password) { $user->forceFill([ 'password' => bcrypt($password), 'remember_token' => Str::random(60), ])->save(); Auth::guard($this->getGuard())->login($user); }
在这个方法里Laravel 用的是bcrypt 加密了密码, 那么要改成我们需要的salt + password的方式,我们在PasswordController类里重写resetPassword方法覆盖掉traits里的该方法就可以了。
/** * 覆盖ResetsPasswords traits里的resetPassword方法,改为用sha1(salt + password)的加密方式 * 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' => $salt, 'remember_token' => Str::random(60), ])->save(); \Auth::guard($this->getGuard())->login($user); }
结语
到这里对Laravel Auth的自定义就完成了,注册、登录和重置密码都改成了sha1(salt + password)的密码加密方式, 所有自定义代码都是通过定义Laravel相关类的子类和重写方法来完成没有修改Laravel的源码,这样既保持了良好的可扩展性也保证了项目能够自由迁移。
注:使用的Laravel版本为5.2
The above is the detailed content of Detailed explanation of user authentication by modifying Laravel Auth to use salt and password. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

LaravelEloquent Model Retrieval: Easily obtaining database data EloquentORM provides a concise and easy-to-understand way to operate the database. This article will introduce various Eloquent model search techniques in detail to help you obtain data from the database efficiently. 1. Get all records. Use the all() method to get all records in the database table: useApp\Models\Post;$posts=Post::all(); This will return a collection. You can access data using foreach loop or other collection methods: foreach($postsas$post){echo$post->

Laravel is a PHP framework for easy building of web applications. It provides a range of powerful features including: Installation: Install the Laravel CLI globally with Composer and create applications in the project directory. Routing: Define the relationship between the URL and the handler in routes/web.php. View: Create a view in resources/views to render the application's interface. Database Integration: Provides out-of-the-box integration with databases such as MySQL and uses migration to create and modify tables. Model and Controller: The model represents the database entity and the controller processes HTTP requests.

When developing websites using CraftCMS, you often encounter resource file caching problems, especially when you frequently update CSS and JavaScript files, old versions of files may still be cached by the browser, causing users to not see the latest changes in time. This problem not only affects the user experience, but also increases the difficulty of development and debugging. Recently, I encountered similar troubles in my project, and after some exploration, I found the plugin wiejeben/craft-laravel-mix, which perfectly solved my caching problem.

Laravel provides a comprehensive Auth framework for implementing user login functions, including: Defining user models (Eloquent model), creating login forms (Blade template engine), writing login controllers (inheriting Auth\LoginController), verifying login requests (Auth::attempt) Redirecting after login is successful (redirect) considering security factors: hash passwords, anti-CSRF protection, rate limiting and security headers. In addition, the Auth framework also provides functions such as resetting passwords, registering and verifying emails. For details, please refer to the Laravel documentation: https://laravel.com/doc

Efficiently process 7 million records and create interactive maps with geospatial technology. This article explores how to efficiently process over 7 million records using Laravel and MySQL and convert them into interactive map visualizations. Initial challenge project requirements: Extract valuable insights using 7 million records in MySQL database. Many people first consider programming languages, but ignore the database itself: Can it meet the needs? Is data migration or structural adjustment required? Can MySQL withstand such a large data load? Preliminary analysis: Key filters and properties need to be identified. After analysis, it was found that only a few attributes were related to the solution. We verified the feasibility of the filter and set some restrictions to optimize the search. Map search based on city

How does Laravel play a role in backend logic? It simplifies and enhances backend development through routing systems, EloquentORM, authentication and authorization, event and listeners, and performance optimization. 1. The routing system allows the definition of URL structure and request processing logic. 2.EloquentORM simplifies database interaction. 3. The authentication and authorization system is convenient for user management. 4. The event and listener implement loosely coupled code structure. 5. Performance optimization improves application efficiency through caching and queueing.

Article summary: This article provides detailed step-by-step instructions to guide readers on how to easily install the Laravel framework. Laravel is a powerful PHP framework that speeds up the development process of web applications. This tutorial covers the installation process from system requirements to configuring databases and setting up routing. By following these steps, readers can quickly and efficiently lay a solid foundation for their Laravel project.

The Laravel framework has built-in methods to easily view its version number to meet the different needs of developers. This article will explore these methods, including using the Composer command line tool, accessing .env files, or obtaining version information through PHP code. These methods are essential for maintaining and managing versioning of Laravel applications.
