> 백엔드 개발 > PHP 튜토리얼 > Laravel이 Auth를 수정하여 솔트 및 비밀번호 인증을 사용하는 방법에 대한 자세한 설명

Laravel이 Auth를 수정하여 솔트 및 비밀번호 인증을 사용하는 방법에 대한 자세한 설명

*文
풀어 주다: 2023-03-19 08:30:01
원래의
2523명이 탐색했습니다.

이 글에서는 Laravel Auth를 수정하여 사용자를 인증하기 위해 솔트와 비밀번호를 사용하는 것에 대한 관련 정보를 주로 소개합니다. 이 글에서는 필요한 모든 사람의 공부나 업무에 대한 특정 참고 학습 가치를 제공합니다. 따라갈 수 있어요 함께 살펴볼까요? 그것이 모두에게 도움이 되기를 바랍니다.

머리말

이 글은 주로 Laravel Auth를 수정하여 사용자를 인증하기 위해 솔트와 비밀번호를 사용하는 관련 내용을 소개합니다. 아래에서는 많은 언급을 하지 않겠습니다. 소개:

라라발의 자체 사용자 인증 시스템 Auth는 매우 강력하고 사용하기 쉽습니다. 그러나 Laravel의 사용자 인증 시스템에서는 사용자 등록, 로그인, 및 비밀번호 검색 모듈을 사용했으며 이전 프로젝트에서는 사용자 테이블에 사용자 비밀번호를 기록하기 위해 솔트 + 비밀번호 암호화 문자열을 저장하는 방법을 사용했는데, 이는 이전 프로젝트를 재구성하기 위해 Laravel 프레임워크를 사용하는 데 큰 저항을 가져왔습니다. 인터넷에서 정보를 검색하고, 커뮤니티 포럼을 읽고, 소스 코드를 읽어보고 Laravel Auth를 수정한 내용을 여기에 공유하여 다른 사람들에게 도움이 되기를 바랍니다. 시작하기 전에 Laravel 프레임워크를 새 프로젝트에서 사용하는 경우 Auth를 수정할 필요가 없다는 점을 설명해야 합니다. 기본 bcrypt 암호화 알고리즘은 salt + 비밀번호보다 더 안전하고 효율적인 암호화 알고리즘입니다.

사용자 등록 수정

먼저 artisan 명령을 사용하여 laravel에서 확인을 활성화합니다

php artisan make:auth
로그인 후 복사

명령을 실행한 후 경로 파일에 추가 정적 메서드가 있습니다(위치: app/Http/routes.dll). php)

Route::auth();
로그인 후 복사
를 호출하세요

이 경로는 Laravel의 Facade(IlluminateSupportFacadesRoute에 있음)입니다. 호출된 인증 메소드는 IlluminateRoutingRouter 클래스에 정의되어 있습니다. 아래에서 볼 수 있듯이 인증 메소드는 인증 관련 라우팅 규칙을 정의합니다

/**
 * 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');
}
로그인 후 복사

You 등록 시 요청되는 컨트롤러 메소드는 AuthController의 등록 메소드입니다. 이 메소드는 IlluminateFoundationAuthRegistersUsers 특성에 정의되어 있습니다.

/**
 * 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());
}
로그인 후 복사

등록 메소드에서 사용자 입력 요청의 데이터가 먼저 처리됩니다. 확인을 위해 AuthController

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',
 ]);
}
로그인 후 복사

의 유효성 검사기 메서드에서 각 입력 필드에 대해 자체 확인 규칙을 정의하기만 하면 됩니다. 그런 다음 아래를 살펴보고 확인이 통과된 후 Laravel은 다음의 생성 메서드를 사용합니다. AuthController를 사용하여 새 사용자를 생성한 다음 새 사용자의 데이터를 사용하여 로그인 Auth::guard($this->getGuard())->login($this->create($request- >all())); Auth::guard($this->getGuard())->login($this->create($request->all()));

所以我们要自定义用户注册时生成用户密码的加密方式只需要修改AuthController的create方法即可。

比如:

/**
 * 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
 ]);
}
로그인 후 복사

修改用户登录

修改登录前我们需要先通过路由规则看一下登录请求的具体控制器和方法,在上文提到的auth方法定义里可以看到

 $this->get('login', 'Auth\AuthController@showLoginForm');
 $this->post('login', 'Auth\AuthController@login');
 $this->get('logout', 'Auth\AuthController@logout');
로그인 후 복사

验证登录的操作是在AppHttpControllersAuthAuthController类的login方法里。打开AuthController发现Auth相关的方法都是通过性状(traits)引入到类内的,在类内use 要引入的traits,在编译时PHP就会把traits里的代码copy到类中,这是PHP5.5引入的特性具体适用场景和用途这里不细讲。 所以AuthController@login方法实际是定义在
IlluminateFoundationAuthAuthenticatesUsers这个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);
}
로그인 후 복사

登录验证的主要操作是在Auth::guard($this->getGuard())->attempt($credentials, $request->has('remember'));这个方法调用中来进行的,Auth::guard($this->getGuard()) 获取到的是IlluminateAuthSessionGuard (具体如何获取的看Auth这个Facade IlluminateAuthAuthManager里的源码)

看一下SessionGuard里attempt 方法是如何实现的:

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是用传递进来的字段从数据库中取出用户数据的,validateCredentials是用来验证密码是否正确的实际过程。

这里需要注意的是$this->provider这个provider是一个实现了IlluminateContractsAuthUserProvider类的provider, 我们看到目录IlluminateAuth下面有两个UserProvider的实现,分别为DatabaseUserProvider和EloquentUserProvider, 但是我们验证密码的时候是通过那个来验证的呢,看一下auth的配置文件

'providers' => [
 'users' => [
 'driver' => 'eloquent',
 'model' => App\User::class, //这个是driver用的Model
 ],
],
로그인 후 복사

这里配置的是driver => eloquent

따라서 사용자 등록 중 사용자 비밀번호 생성을 위한 암호화 방법을 사용자 정의하려면 AuthController의 생성 방법만 수정하면 됩니다.

🎜예: 🎜
/**
 * 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());
}
로그인 후 복사
로그인 후 복사
🎜🎜🎜사용자 로그인 수정🎜🎜🎜🎜🎜로그인을 수정하기 전에 먼저 인증 방법 정의에서 볼 수 있는 라우팅 규칙을 통해 로그인 요청의 특정 컨트롤러와 방법을 살펴봐야 합니다. 위에서 언급한 🎜
/**
 * The table associated to this model
 */
protected $table = 'user';//用户表名不是laravel约定的这里要指定一下
로그인 후 복사
로그인 후 복사
🎜에 대한 로그인을 확인하는 작업은 AppHttpControllersAuthAuthController 클래스의 login 메소드에 있습니다. AuthController를 열고 Auth 관련 메소드가 모두 특성을 통해 클래스에 도입되었는지 확인합니다. 컴파일하는 동안 PHP는 특성의 코드를 클래스에 복사합니다. 적용 가능한 시나리오와 도입된 기능의 사용은 여기에서 자세히 설명하지 않습니다. 따라서 AuthController@login 메소드는 실제로 🎜IlluminateFoundationAuthAuthenticatesUsers 특성에 정의됩니다. 🎜
/**
 * 禁用Laravel自动管理timestamp列
 */
public $timestamps = false;

/**
 * 覆盖Laravel中默认的getAuthPassword方法, 返回用户的password和salt字段
 * @return type
 */
public function getAuthPassword()
{
 return ['password' => $this->attributes['password'], 'salt' => $this->attributes['salt']];
}
로그인 후 복사
로그인 후 복사
🎜로그인 확인의 주요 작업은 Auth::guard($this->getGuard())에 있습니다. ->attempt($credentials, $request->has('remember'));이 메소드는 Auth::guard($this->getGuard()) 얻은 것은 IlluminateAuthSessionGuard입니다(자세한 내용은 Auth Facade IlluminateAuthAuthManager의 소스 코드 참조)🎜🎜SessionGuard의 시도 메소드가 어떻게 구현되는지 살펴보세요:🎜
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'];
 }
}
로그인 후 복사
로그인 후 복사
🎜retrieveByCredentials는 전달된 필드를 사용하여 데이터베이스에서 검색됩니다. 사용자 데이터의 경우 , verifyCredentials는 비밀번호가 올바른지 확인하는 데 사용되는 실제 프로세스입니다. 🎜🎜여기서 주목해야 할 것은 $this->provider입니다. 이 공급자는 IlluminateContractsAuthUserProvider 클래스를 구현하는 공급자입니다. IlluminateAuth 디렉토리 아래에 두 개의 UserProvider 구현, 즉 DatabaseUserProvider가 있다는 것을 알 수 있습니다. EloquentUserProvider. 그런데 비밀번호를 확인할 때 어떤 비밀번호를 사용하는지 확인해보세요🎜
'providers' => [
 'users' => [
  'driver' => 'admin-eloquent',
  'model' => App\User::class,
 ]
]
로그인 후 복사
로그인 후 복사
🎜 여기서 구성은 driver => eloquent이므로 다음을 통해 확인됩니다. EloquentUserProvider의retrieveByCredentials. 이 EloquentUserProvider는 SessionGuard가 인스턴스화될 때 주입됩니다. (인증 구성 파일을 읽고 해당 제공자를 인스턴스화하여 SessionGuard에 주입하는 방법에 대한 자세한 내용은 IlluminateAuthAuthManager의 createSessionDriver 메소드 소스 코드를 참조하세요.)🎜 🎜계속해서 EloquentUserProvider에서retrieveByCredentials 및 verifyCredentials 메소드의 구현을 확인해 보세요: 🎜
/**
 * 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

相关推荐:

Laravel 5.5的可相应接口如何使用?

Laravel Redis 多个进程同时取队列问题

laravel编写APP接口(API)

위 내용은 Laravel이 Auth를 수정하여 솔트 및 비밀번호 인증을 사용하는 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿