Laravel 사용자 인증 시스템 구현 내용

不言
풀어 주다: 2023-04-02 16:56:01
원래의
2348명이 탐색했습니다.

이 글은 주로 Laravel 사용자 인증 시스템의 구현 세부 사항을 소개하며, 이는 특정 참조 가치가 있습니다. 이제 여러분과 공유합니다. 도움이 필요한 친구들이 참고할 수 있습니다

사용자 인증 시스템 구현 세부 사항

소개했습니다. 이전 섹션에서 Laravel Auth 시스템의 기본 지식을 통해 핵심 구성 요소가 무엇인지 설명했습니다. 이번 섹션에서는 주로 Auth를 중심으로 Laravel Auth 시스템의 구현 세부 사항에 중점을 둘 것입니다. 또한 AuthManager는 인증 가드(Guard)와 사용자 공급자(UserProvider)를 로드하는 방법과 기본 사용자 등록 및 로그인의 구현 세부 사항을 정렬하여 알 수 있습니다. 사용자 인증을 위한 자체 프로젝트 요구 사항을 충족하도록 인증 인증을 사용자 정의합니다. Auth也就是AuthManager是如何装载认证用的看守器(Guard)和用户提供器(UserProvider)以及默认的用户注册和登录的实现细节,通过梳理这些实现细节我们也就能知道应该如何定制Auth认证来满足我们自己项目中用户认证的需求的。

通过AuthManager装载看守器和用户提供器

AuthManager装载看守器和用户提供器用到的方法比较多,用文字描述不太清楚,我们通过注解这个过程中用到的方法来看具体的实现细节。

namespace Illuminate\Auth;

class AuthManager implements FactoryContract
{
    /**
     * 尝试从$guards属性中获取指定的Guard
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
     */
    public function guard($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return isset($this->guards[$name])
                    ? $this->guards[$name]
                    : $this->guards[$name] = $this->resolve($name);
    }
    
    /**
     * 解析出给定name的Guard
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
     *
     * @throws \InvalidArgumentException
     */
    protected function resolve($name)
    {
        //获取Guard的配置
        //$config = ['driver' => 'session', 'provider' => 'users']
        $config = $this->getConfig($name);

        if (is_null($config)) {
            throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
        }
       //如果通过extend方法为guard定义了驱动器,这里去调用自定义的Guard驱动器
        if (isset($this->customCreators[$config['driver']])) {
            return $this->callCustomCreator($name, $config);
        }
        //Laravel auth默认的配置这里是执行createSessionDriver
        $driverMethod = 'create'.ucfirst($config['driver']).'Driver';

        if (method_exists($this, $driverMethod)) {
            return $this->{$driverMethod}($name, $config);
        }

        throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
    }
    
    /**
     * 从config/auth.php中获取给定名称的Guard的配置
     *
     * @param  string  $name
     * @return array
     */
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],
    protected function getConfig($name)
    {
        //'guards' => [
        //    'web' => [
        //        'driver' => 'session',
        //        'provider' => 'users',
        //    ],

        //    'api' => [
        //        'driver' => 'token',
        //        'provider' => 'users',
        //    ],
        //],
        // 根据Laravel默认的auth配置, 这个方法会获取key "web"对应的数组
        return $this->app['config']["auth.guards.{$name}"];
    }
    
    /**
     * 调用自定义的Guard驱动器
     *
     * @param  string  $name
     * @param  array  $config
     * @return mixed
     */
    protected function callCustomCreator($name, array $config)
    {
        return $this->customCreators[$config['driver']]($this->app, $name, $config);
    }
    
    /**
     * 注册一个自定义的闭包Guard 驱动器 到customCreators属性中
     *
     * @param  string  $driver
     * @param  \Closure  $callback
     * @return $this
     */
    public function extend($driver, Closure $callback)
    {
        $this->customCreators[$driver] = $callback;

        return $this;
    }
    
    /**
     * 注册一个自定义的用户提供器创建器到 customProviderCreators属性中
     *
     * @param  string  $name
     * @param  \Closure  $callback
     * @return $this
     */
    public function provider($name, Closure $callback)
    {
        $this->customProviderCreators[$name] = $callback;

        return $this;
    }
    
    /**
     * 创建基于session的认证看守器 SessionGuard
     *
     * @param  string  $name
     * @param  array  $config
     * @return \Illuminate\Auth\SessionGuard
     */
    public function createSessionDriver($name, $config)
    {
        //$config['provider'] == 'users'
        $provider = $this->createUserProvider($config['provider'] ?? null);

        $guard = new SessionGuard($name, $provider, $this->app['session.store']);

        if (method_exists($guard, 'setCookieJar')) {
            $guard->setCookieJar($this->app['cookie']);
        }

        if (method_exists($guard, 'setDispatcher')) {
            $guard->setDispatcher($this->app['events']);
        }

        if (method_exists($guard, 'setRequest')) {
            $guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
        }

        return $guard;
    }
    
    //创建Guard驱动依赖的用户提供器对象
    public function createUserProvider($provider = null)
    {
        if (is_null($config = $this->getProviderConfiguration($provider))) {
            return;
        }
        //如果通过Auth::provider方法注册了自定义的用户提供器creator闭包则去调用闭包获取用户提供器对象
        if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
            return call_user_func(
                $this->customProviderCreators[$driver], $this->app, $config
            );
        }

        switch ($driver) {
            case 'database':
                return $this->createDatabaseProvider($config);
            case 'eloquent':
                //通过默认的auth配置这里会返回EloquentUserProvider对象,它实现了Illuminate\Contracts\Auth 接口
                return $this->createEloquentProvider($config);
            default:
                throw new InvalidArgumentException(
                    "Authentication user provider [{$driver}] is not defined."
                );
        }
    }
    
    /**
     * 会通过__call去动态地调用AuthManager代理的Guard的用户认证相关方法
     * 根据默认配置,这里__call会去调用SessionGuard里的方法
     * @param  string  $method
     * @param  array  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        return $this->guard()->{$method}(...$parameters);
    }
}
로그인 후 복사

注册用户

Laravel Auth系统中默认的注册路由如下:

$this->post('register', 'Auth\RegisterController@register');
로그인 후 복사

所以用户注册的逻辑是由RegisterController的register方法来完成的

class RegisterController extends Controller
{
    //方法定义在Illuminate\Foundation\Auth\RegisterUsers中
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        return $this->registered($request, $user)
        
     }
     
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
        ]);
    }
    
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
        ]);
    }
         
}
로그인 후 복사

register的流程很简单,就是验证用户输入的数据没问题后将这些数据写入数据库生成用户,其中密码加密采用的是bcrypt算法,如果你需要改成常用的salt加密码明文做哈希的密码加密方法可以在create方法中对这部分逻辑进行更改,注册完用户后会调用SessionGuard的login方法把用户数据装载到应用中,注意这个login方法没有登录认证,只是把认证后的用户装载到应用中这样在应用里任何地方我们都能够通过Auth::user()来获取用户数据啦。

用户登录认证

Laravel Auth系统的登录路由如下

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

我们看一下LoginController里的登录逻辑

class LoginController extends Controller
{
    /**
     * 处理登录请求
     */
    public function login(Request $request)
    {
        //验证登录字段
        $this->validateLogin($request);
        //防止恶意的多次登录尝试
        if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return $this->sendLockoutResponse($request);
        }
        //进行登录认证
        if ($this->attemptLogin($request)) {
            return $this->sendLoginResponse($request);
        }

        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }
    
    //尝试进行登录认证
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->filled('remember')
        );
    }
    
    //获取登录用的字段值
    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }
}
로그인 후 복사

可以看到,登录认证的逻辑是通过SessionGuardattempt方法来实现的,其实就是Auth::attempt(), 下面我们来看看attempt方法里的逻辑:

class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);

        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
       //如果登录认证通过,通过login方法将用户对象装载到应用里去
        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);

            return true;
        }
        //登录失败的话,可以触发事件通知用户有可疑的登录尝试(需要自己定义listener来实现)
        $this->fireFailedEvent($user, $credentials);

        return false;
    }
    
    protected function hasValidCredentials($user, $credentials)
    {
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
    }
}
로그인 후 복사

SessionGuardattempt方法首先通过用户提供器的retriveBycredentials方法通过用户名从用户表中查询出用户数据,认证用户信息是通过用户提供器的validateCredentials来实现的,所有用户提供器的实现类都会实现UserProvider契约(interface)中定义的方法,通过上面的分析我们知道默认的用户提供器是EloquentUserProvider

class EloquentUserProvider implements UserProvider
{
    从数据库中取出用户实例
    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists('password', $credentials))) {
            return;
        }

        $query = $this->createModel()->newQuery();

        foreach ($credentials as $key => $value) {
            if (! Str::contains($key, 'password')) {
                $query->where($key, $value);
            }
        }

        return $query->first();
    }
    
    //通过给定用户认证数据来验证用户
    public function validateCredentials(UserContract $user, array $credentials)
    {
        $plain = $credentials['password'];

        return $this->hasher->check($plain, $user->getAuthPassword());
    }
}

class BcryptHasher implements HasherContract
{
    //通过bcrypt算法计算给定value的散列值
    public function make($value, array $options = [])
    {
        $hash = password_hash($value, PASSWORD_BCRYPT, [
            'cost' => $this->cost($options),
        ]);

        if ($hash === false) {
            throw new RuntimeException('Bcrypt hashing not supported.');
        }

        return $hash;
    }
    
    //验证散列值是否给定明文值通过bcrypt算法计算得到的
    public function check($value, $hashedValue, array $options = [])
    {
        if (strlen($hashedValue) === 0) {
            return false;
        }

        return password_verify($value, $hashedValue);
    }
}
로그인 후 복사

用户密码的验证是通过EloquentUserProvider依赖的hasher哈希器来完成的,Laravel认证系统默认采用bcrypt算法来加密用户提供的明文密码然后存储到用户表里的,验证时haser哈希器的check方法会通过PHP内建方法password_verify来验证明文密码是否是存储的密文密码的原值。

用户认证系统的主要细节梳理完后我们就知道如何定义我们自己的看守器(Guard)或用户提供器(UserProvider)了,首先他们必须实现各自遵守的契约里的方法才能够无缝接入到Laravel的Auth系统中,然后还需要将自己定义的Guard或Provider通过Auth::extendAuth::provider

AuthManager를 통한 감시자 및 사용자 공급자 로드

AuthManager는 감시자 및 사용자 공급자를 로드하기 위해 많은 메소드를 사용하며, 말로 설명은 명확하지 않습니다. 이 프로세스에서 사용되는 메소드에 대해서는 주석을 달겠습니다. 구현 세부 사항.

rrreee

등록된 사용자

Laravel 인증 시스템의 기본 등록 경로는 다음과 같습니다:

rrreee

그래서 사용자 등록 로직은 RegisterController의 등록 메소드에 의해 완료됩니다

rrreee

등록 프로세스는 매우 사용자가 입력한 데이터가 정확하면 데이터가 데이터베이스에 기록되어 사용자를 생성합니다. 비밀번호 암호화는 일반적으로 사용되는 일반 솔트 암호화 방법으로 변경해야 하는 경우 bcrypt 알고리즘을 사용합니다. 텍스트 해싱은 생성 메소드에서 수행할 수 있습니다. 사용자를 등록한 후 SessionGuard의 로그인 메소드가 호출되어 사용자 데이터를 애플리케이션에 로드합니다. 로그인 인증을 수행하지만 인증된 사용자만 애플리케이션에 로드하므로 Auth::user()를 통해 사용자 데이터를 얻을 수 있습니다.

사용자 로그인 인증

Laravel Auth 시스템의 로그인 경로는 다음과 같습니다rrreee
LoginController의 로그인 로직을 살펴보겠습니다rrreee

로그인 인증의 로직은 다음과 같습니다. SessionGuardAuth::attempt()attempt 메서드에 의해 구현됩니다. >attempt 메서드: rrreeeSessionGuardattempt 메서드는 먼저 사용자 공급자의 를 통해 사용자 이름을 통해 사용자 테이블의 사용자 데이터를 쿼리합니다. retriveBycredentials 메서드를 사용하고 사용자 정보를 인증합니다. 이는 사용자 공급자의 validateCredentials를 통해 구현됩니다. 모든 사용자 공급자 구현 클래스는 UserProvider 계약(인터페이스)을 통해 정의됩니다. 위 분석을 통해 우리는 기본 사용자 공급자가 EloquentUserProvider
rrreee

라는 것을 알고 있습니다. 사용자 비밀번호 확인은 EloquentUserProvider가 의존하는 hasher 해셔를 통해 완료됩니다. Laravel 인증 시스템은 기본적으로 암호화를 위해 bcrypt 알고리즘을 사용합니다. 그런 다음 사용자가 제공한 일반 텍스트 비밀번호는 확인 중에 hasercheck 메소드에 저장됩니다. /code> 해셔는 일반 텍스트 비밀번호가 저장된 암호문 비밀번호의 원래 값인지 확인하기 위해 PHP 내장 메소드 password_verify를 전달합니다. 🎜🎜사용자 인증 시스템의 주요 세부 사항을 정리한 후 이제 우리는 자체 Guard 또는 UserProvider를 정의하는 방법을 알게 되었습니다. 먼저 Laravel의 인증 시스템에 원활하게 액세스하기 전에 준수하는 계약에 메서드를 구현해야 합니다. 그런 다음 Auth::extendAuth::provider 메서드를 통해 자신이 정의한 Guard 또는 Provider를 등록하여 Guard 또는 Provider 인스턴스의 폐쇄를 반환해야 합니다. Laravel에 패키지되어 있으므로 Guard 및 UserProvider의 사용자 정의가 완전한 세트일 필요는 없습니다. Guard를 별도로 사용자 정의하고 기본 EloquentUserProvider를 계속 사용하거나 기본 SessionGuard가 사용자 정의된 UserProvider를 사용하도록 할 수 있습니다. 🎜🎜다음 섹션에서는 Laravel Auth 시스템을 확장하는 방법을 더 잘 설명하기 위해 이전 프로젝트 개발에 사용된 사례를 제공하겠습니다. 🎜🎜위 내용은 이 글의 전체 내용입니다. 모든 분들의 학습에 도움이 되었으면 좋겠습니다. 더 많은 관련 내용은 PHP 중국어 홈페이지를 주목해주세요! 🎜🎜관련 권장사항: 🎜🎜🎜Laravel WeChat 애플릿은 매개변수를 사용하여 사용자 세부정보와 애플릿 코드 확장 분석을 얻습니다.🎜🎜🎜🎜🎜Laravel 서비스 컨테이너 사용의 장점🎜🎜🎜

위 내용은 Laravel 사용자 인증 시스템 구현 내용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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