资讯专栏INFORMATION COLUMN

Laravel中的Auth

张汉庆 / 3593人阅读

摘要:中的中有一个组件叫,组件提供了整个框架的认证功能,这里想简单追踪一下它的实现逻辑。

Laravel中的Auth

laravel中有一个组件叫auth,auth组件提供了整个框架的认证功能,这里想简单追踪一下它的实现逻辑。

首先从 php artisan make:auth 开始
# IlluminateAuthConsoleAuthMakeCommand.php

public function handle()
{
    // 创建存放auth前端界面的目录和文件
    // 模版存放在AuthConsole的stubs下
    $this->createDirectories();
    $this->exportViews();

    if (! $this->option("views")) {
        // 生成HomeController控制器文件
        file_put_contents(
            app_path("Http/Controllers/HomeController.php"),
            $this->compileControllerStub()
        );
        // 生成auth相关路由
    file_put_contents(
        base_path("routes/web.php"),
        file_get_contents(__DIR__."/stubs/make/routes.stub"),
        FILE_APPEND
        );
    }
}

生成文件resources/views/auth、 resources/layouts路由文件 web.php 、和 Http/Controllers/Auth 下的控制器

说一说csrf-token

        function csrf_token()
    {
        $session = app("session");

        if (isset($session)) {
            return $session->token();
        }

        throw new RuntimeException("Application session store not set.");
    }

LoginController的login方法
    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);
    }

登录验证方法attemptLogin

通过 Auth::guard() 引导到 IlluminateAuthAuthManager
先看  服务提供者  AuthServiceProvider
AuthServiceProvider注册四个服务

protected function registerAuthenticator()
    {
        $this->app->singleton("auth", function ($app) {
            $app["auth.loaded"] = true;
                        // 生成一个AuthManager实例
            return new AuthManager($app);
        });

        $this->app->singleton("auth.driver", function ($app) {
            return $app["auth"]->guard();
        });
    }
protected function registerUserResolver()
    {
        $this->app->bind(
            AuthenticatableContract::class, function ($app) {
                return call_user_func($app["auth"]->userResolver());
            }
        );
    }
protected function registerAccessGate()
    {
        $this->app->singleton(GateContract::class, function ($app) {
            return new Gate($app, function () use ($app) {
                return call_user_func($app["auth"]->userResolver());
            });
        });
    }
protected function registerRequestRebindHandler()
    {
        $this->app->rebinding("request", function ($app, $request) {
            $request->setUserResolver(function ($guard = null) use ($app) {
                return call_user_func($app["auth"]->userResolver(), $guard);
            });
        });
    }

生成一个AuthManager实例
AuthManager中的trait CreatesUserProviders
这个trait是用来绑定一个用户认证的Eloqument服务提供者

public function __construct($app)
    {
                // 绑定application实例
        $this->app = $app;
                // 绑定一个闭包,用于解析用户。
                // 通过$guard来确定用户解析用户的方法
        $this->userResolver = function ($guard = null) {
            return $this->guard($guard)->user();
        };
    }

protected function resolve($name)
    {
        $config = $this->getConfig($name);

                // 根据配置调用不同的解析用户的驱动方法
        $driverMethod = "create".ucfirst($config["driver"])."Driver";

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

分别定位的两个方法

        public function createSessionDriver($name, $config)
    {
                //     根据配置文件创建一个相应的provider
        $provider = $this->createUserProvider($config["provider"] ?? null);
                
                $guard = new SessionGuard($name, $provider, $this->app["session.store"]);

        return $guard;
    }
    
    public function createTokenDriver($name, $config)
    {
        $guard = new TokenGuard(
            $this->createUserProvider($config["provider"] ?? null),
            $this->app["request"],
            $config["input_key"] ?? "api_token",
            $config["storage_key"] ?? "api_token"
        );
        return $guard;
    }

于是得到 $this->guard($guard) 的user()方法
先看如何实例一个TokenGuard类

public function __construct(UserProvider $provider, Request $request, $inputKey = "api_token", $storageKey = "api_token")
    {
        $this->request = $request;
        $this->provider = $provider;
        $this->inputKey = $inputKey;
        $this->storageKey = $storageKey;
    }
# IlluminateAuthTokenGuard

    public function user()
    {
        if (! is_null($this->user)) {
            return $this->user;
        }

        $user = null;
                // 从request中获取token
        $token = $this->getTokenForRequest();

        if (! empty($token)) {
                        // 通过用户provider中的retrieveByCredentials方法来判断用户是否认证成功
            $user = $this->provider->retrieveByCredentials(
                [$this->storageKey => $token]
            );
        }

        return $this->user = $user;
    }

上面都是通用的加载引导调用功能,下面的用户服务提供者则是可以修改自定义的认证的具体功能

认证绑定的用户数据提供者
# IlluminateAuthDatabaseUserProvider

    public function retrieveByCredentials(array $credentials)
    {
        if (empty($credentials) ||
           (count($credentials) === 1 &&
            array_key_exists("password", $credentials))) {
            return;
        }
        $query = $this->conn->table($this->table);

        foreach ($credentials as $key => $value) {
            if (Str::contains($key, "password")) {
                continue;
            }

            if (is_array($value) || $value instanceof Arrayable) {
                $query->whereIn($key, $value);
            } else {
                $query->where($key, $value);
            }
        }
        
        $user = $query->first();
        
        // 返回auth用户数据包
        return $this->getGenericUser($user);
    }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/31681.html

相关文章

  • Laravel 多用户认证系统改造方案

    摘要:本文基于,主要介绍如何针对多站点分别进行用户认证的改造,用意是最大限度利用自带的认证系统。具体方案为清晰起见,项目按照不同站点组织成不同模块。学院版用户认证文档版用户认证文档更详细学院版验证文档版验证文档更详细翁航版多用户认证方案 原文发表于 http://www.jianshu.com/p/d6c112f27661 showImg(https://segmentfault.com/i...

    paulli3 评论0 收藏0
  • Laravel 获取当前 Guard 分析 —源自电商购物车的实际需求

    摘要:因为客户希望能够直观的看到目前购物车中商品信息,以便推送优惠信息来促使转化。用户在商城中的购物车数据导购使用导购小程序代用户下单或结账时加入的购物车数据,不和用户购物车数据同步。 iBrand 产品中关于购物车的需求比较复杂,我们基于 overture/laravel-shopping-cart 扩展出了更加符合电商需求的购物车包,之前有文章进行过简单的介绍: Laravel shop...

    daydream 评论0 收藏0
  • API Token Authentication

    摘要:新增了很多的新特性,包括了内置多用户认证表单数组输入验证隐式路由模型绑定中间件组的定义中间件访问频率限制等主要功能。相对于变化有点大,简化了的目录结构,并将路由分离出来。由于已将的路由单独分离出来,因此只需在中添加路由规则。 Laravel 5.2 新增了很多的新特性,包括了内置多用户认证、表单数组输入验证、隐式路由模型绑定、中间件组的定义、中间件 throttle 访问频率限制等主要...

    KitorinZero 评论0 收藏0
  • Lumen用户认证JWT,源码解读

    摘要:如何做用户认证根据文档描述,提供用户认证的接口,他的核心是看守器和提供器,看守器定义怎么认证用户,提供器定义怎么检索用户。 最近的一个PHP项目,上一个项目是采用ThinkPHP来弄的,因为很早就听说过Laravel的大名,所以进了Laravel的官网,意外发现了Lumen,正好我项目是提供API的,所以选择了Lumen,因为是Laravel的精简版,看了几天的Laravel文档,也总...

    AZmake 评论0 收藏0
  • Laravel 5.2 Auth 认证解析以及改用 salt+passwrod 加密验证

    摘要:本文来源于本人博客认证解析以及改用加密验证的默认登陆传入邮件和用户密码到方法来认证,通过的值获取,如果用户被找到,经哈希运算后存储在数据中的将会和传递过来的经哈希运算处理的值进行比较。 本文来源于本人博客: Laravel 5.2 Auth 认证解析以及改用 salt+passwrod 加密验证 Larval 5.2的默认Auth登陆传入邮件和用户密码到attempt 方法来认证,通过...

    binaryTree 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<