• 技术文章 >php框架 >Laravel

    关于Laravel Auth原理浅析

    藏色散人藏色散人2020-08-07 16:01:02转载1519
    下面由Laravel教程栏目给大家介绍Laravel Auth原理浅析,希望对需要的朋友有所帮助!

    由于公司最近使用Laravel-admin做后台,接触了下Laravel框架,不得不说,Laravel社区的力量以及生态确实挺强大。

      但是公司内部业务都处于Java端,后台全部都是调JavaApi,因此使用Laravel的特性就得大打折扣了,首先Eloquent模型完全不能用,我这边把业务分开来,只存了3张表,这是Laravel-admin自带的表。

    企业微信截图_15967872395039.png

      Laravel-admin带了9张表,由于用户登录业务全保存在Api端,自带的表功能被我割舍了。因此需要自己实现Api登录的逻辑,而又必须走Laravel Auth认证。

    原理解读

    // 使用下面这个命令Laravel会自动为我们生成Auth路由和认证模块。跟着代码往下解读。
      php artisan make:auth 
      
    // Http/Controllers/Auth/LoginController 使用了 AuthenticatesUsers

    其中 下面这三个方法诠释了登录逻辑的全部。

    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->has('remember')
            );
        }
        protected function guard()
        {
            return Auth::guard();
        }

    控制器会去寻找Auth::guard(), 那这个Auth::guard()是个什么东西呢,

    首先 Auth 是系统的单例,原型在

    Illuminate\Auth\AuthManager;

    顾名思义,是一个Auth管理模块,实现了认证工厂模式接口guards(),

    public function __construct($app)
        {
            $this->app = $app;
            $this->userResolver = function ($guard = null) {
                return $this->guard($guard)->user();
            };
        }
        // Auth::guard();就是调用了这个方法。
        public function guard($name = null)
        {
            // 首先查找$name, 没有就使用默认的驱动,
            $name = $name ?: $this->getDefaultDriver();
            // 意思就是要实例化出这个驱动并且返回,
            return isset($this->guards[$name])
                        ? $this->guards[$name]
                        : $this->guards[$name] = $this->resolve($name);
        }
       
        // 默认的驱动是从配置文件里面读取的,/config/auth.php default配置项
        public function getDefaultDriver()
        {
            return $this->app['config']['auth.defaults.guard'];
        }
      
       // 这里是构造Auth-guard驱动
       protected function resolve($name)
        {
            $config = $this->getConfig($name);
            if (is_null($config)) {
                throw new InvalidArgumentException("xxx");
            }
            // 这里是如果你自己实现的驱动就返回
            if (isset($this->customCreators[$config['driver']])) {
                return $this->callCustomCreator($name, $config);
            }
            // 这里是系统默认两个类分别是 
           // session 和 token 这里主要讲 sessionGuard .
            $driverMethod = 'create'.ucfirst($config['driver']).'Driver';
            if (method_exists($this, $driverMethod)) {
                return $this->{$driverMethod}($name, $config);
            }
            throw new InvalidArgumentException("xxx");
        }

    接下来看看配置文件 auth.php

     // Auth::guard() ,不传参数,就调用默认的default.guard ,
       'defaults' => [
            'guard' => 'web',
            'passwords' => 'users',
        ],
       // 系统的guard .默认支持 "database", "eloquent",意思就是说你的provider必须是这两个实例中的一个,
        'guards' => [
            'web' => [
                'driver' => 'session',
                'provider' => 'users',
            ],
            'api' => [
                'driver' => 'token',
                'provider' => 'users',
            ],
        ],
      // 这个就是上面的provider了,你使用哪一个provider作为你的Auth::guard()返回的
     // 模型
        'providers' => [
            'users' => [
                'driver' => 'eloquent',
                'model' => App\User::class,
            ],
            // 'users' => [
            //     'driver' => 'database',
            //     'table' => 'users',
            // ],
        ],

    也就是说终归到底,Auth::guard(), 在默认配置里面是给我反回了一个sessionGuard .

    主要看下面4个方法

    namespace Illuminate\Auth;
    class SessionGuard{
        public function attempt(array $credentials = [], $remember = false)
        {
            // 这里触发 试图登录事件,此时还没有登录
            $this->fireAttemptEvent($credentials, $remember);
            $this->lastAttempted = 
            $user = $this->provider->retrieveByCredentials($credentials);
            // 这里会调用hasValidCredentials,其实就是验证用户名和密码的一个过程
            if ($this->hasValidCredentials($user, $credentials)) {
                // 如果验证通过了,就调用login方法 .
                $this->login($user, $remember);
                return true;
            }
            // 否则就触发登录失败事件,返回假
            $this->fireFailedEvent($user, $credentials);
            return false;
        }
        // 这里是登录用户的操作,就是说调用这个方法已经是合法用户了,必须是一个
      // AuthenticatableContract 的实例 .
        public function login(AuthenticatableContract $user, 
        $remember = false)
        {
            // 直接更新session,这里就是把session存起来,session的键在该方法的
            // getName() 里边,
            $this->updateSession($user->getAuthIdentifier());
            if ($remember) {
                $this->ensureRememberTokenIsSet($user);
                $this->queueRecallerCookie($user);
            }
         // 触发登录事件,已经登录了这个时候,
            $this->fireLoginEvent($user, $remember);
            // 将user对象保存到sessionGuard , 后续的类访问Auth::user();直接拿到
            $this->setUser($user);
        }
        // 这里就是经常使用到的 Auth::user()了,具体如何返回看AuthManager里面的
        // __call
        public function user()
        {
            if ($this->loggedOut) {
                return;
            }
            if (! is_null($this->user)) {
                return $this->user;
            }
            // 这里读取session拿到user的id ,
            $id = $this->session->get($this->getName());
            $user = null;
            // 如果拿到了id ,查找到该user
            if (! is_null($id)) {
                if ($user = $this->provider->retrieveById($id)) {
                    $this->fireAuthenticatedEvent($user);
                }
            }
            $recaller = $this->recaller();
            if (is_null($user) && ! is_null($recaller)) {
                $user = $this->userFromRecaller($recaller);
                if ($user) {
                    $this->updateSession($user->getAuthIdentifier());
                    $this->fireLoginEvent($user, true);
                }
            }
            return $this->user = $user;
        }
        // 这里就直接返回用户id了,
        public function id()
        {
            if ($this->loggedOut) {
                return;
            }
            return $this->user()
                        ? $this->user()->getAuthIdentifier()
                        : $this->session->get($this->getName());
        }
    }

    大体上用户登录的流程就完了,简单过程就是

    //伪代码
    $credentials = $request()->only(['username' ,'password']);
    if(Auth::guard("session")->attempt($credentials)){
      // 登录成功
    }else{
      // 登录失败
    }

    实现用户登录之后才能访问的控制器/方法

    Route::get("/home")->middleware("auth");
    // auth Middleware 是在app/Http/Kernel中注册的,
    // 类名是  \Illuminate\Auth\Middleware\Authenticate::class
    // 解析过程实质上是这个方法:
        public function handle($request, Closure $next, ...$guards)
        {
            $this->authenticate($guards);
            return $next($request);
        }
      
        protected function authenticate(array $guards)
        {  
            // 默认情况下会去 Auth中寻找authenticate这个方法
            if (empty($guards)) {
                return $this->auth->authenticate();
            }
            // 如果middleware中传了参数,会遍历一遍,不通过就抛出异常
            foreach ($guards as $guard) {
                if ($this->auth->guard($guard)->check()) {
                    return $this->auth->shouldUse($guard);
                }
            }
            throw new AuthenticationException('Unauthenticated.', $guards);
        }
        //sessionGuard 中的authenticate其实也就是调用了一遍user方法。
        public function authenticate()
        {
            if (! is_null($user = $this->user())) {
                return $user;
            }
            throw new AuthenticationException;
        }

    第一次写文,有错误请指出谢谢!

    以上就是关于Laravel Auth原理浅析的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:zhuanlan,如有侵犯,请联系admin@php.cn删除
    专题推荐:Laravel Auth
    上一篇:Laravel8 将于9月8日发布啦! 下一篇:Laravel-admin弹窗table组件【改】
    大前端线上培训班

    相关文章推荐

    • 教你掌握 Laravel 的测试方法• Laravel使用intervention image包上传、剪裁图片• 教你使用Orator将你的SQL转换为Laravel Query语句• Laravel8 将于9月8日发布啦!

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网