Laravel中的Auth

栏目: 编程语言 · PHP · 发布时间: 4年前

内容简介:laravel中有一个组件叫auth,auth组件提供了整个框架的认证功能,这里想简单追踪一下它的实现逻辑。生成文件通过

Laravel中的Auth

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

首先从 php artisan make:auth 开始

# Illuminate\Auth\Console\AuthMakeCommand.php

public function handle()
{
    // 创建存放auth前端界面的目录和文件
    // 模版存放在Auth\Console的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

<!-- CSRF Token -->
<meta name="csrf-token" content="{{ 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() 引导到 Illuminate\Auth\AuthManager
先看  服务提供者   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;
    }
# Illuminate\Auth\TokenGuard

    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;
    }

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

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

# Illuminate\Auth\DatabaseUserProvider

    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);
    }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

正则表达式必知必会(修订版)

正则表达式必知必会(修订版)

福达 (Ben Forta) / 杨涛 / 人民邮电出版社 / 2015-1-1 / 29.00元

《正则表达式必知必会》从简单的文本匹配开始,循序渐进地介绍了很多复杂内容,其中包括回溯引用、条件性求值和前后查找,等等。每章都为读者准备了许多简明又实用的示例,有助于全面、系统、快速掌握正则表达式,并运用它们去解决实际问题。正则表达式是一种威力无比强大的武器,几乎在所有的程序设计语言里和计算机平台上都可以用它来完成各种复杂的文本处理工作。而且书中的内容在保持语言和平台中立的同时,还兼顾了各种平台之......一起来看看 《正则表达式必知必会(修订版)》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试