看到Laravel-China社区常有人问Laravel Passport用于密码验证方式来获取Token的问题,刚好我最近一个API项目使用Laravel Dingo Api+Passport,也是使用Oauth2 的'grant_type' => 'password'密码授权来做Auth验证,对于如何做登录登出,以及多账号系统的认证等常用场景做一下简单的使用小总结。 基本配置 基本安装配置主要参照官方文档,具体不详细说,列出关键代码段 config/auth.php 'guards' => [ 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => \App\Models\User::class ], ], Providers/AuthServiceProvider.php public function boot() { $this->registerPolicies(); //默认令牌发放的有效期是永久 //Passport::tokensExpireIn(Carbon::now()->addDays(2)); //Passport::refreshTokensExpireIn(Carbon::now()->addDays(4)); Passport::routes(function (RouteRegistrar $router) { //对于密码授权的方式只要这几个路由就可以了 config(['auth.guards.api.provider' => 'users']); $router->forAccessTokens(); }); } Middleware/AuthenticateApi.php 自定义中间件返回 <?php namespace App\Http\Middleware; use Closure; use Illuminate\Auth\Middleware\Authenticate; use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; class AuthenticateApi extends Authenticate { protected function authenticate(array $guards) { if ($this->auth->guard('api')->check()) { return $this->auth->shouldUse('api'); } throw new UnauthorizedHttpException('', 'Unauthenticated'); } } App/Http/Kernel.

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接 https://divinglaravel.com/queue-system/workers 现在,我们知道了Laravel如何将作业推到不同的队列中,让我们来深入了解workers如何运作你的作业。 首先,我将workers定义为一个在后台运行的简单PHP进程,目的是从存储空间中提取作业并针对多个配置选项运行它们。 php artisan queue:work 运行此命令将指示Laravel创建应用程序的一个实例并开始执行作业,这个实例将一直存活着,启动Laravel应用程序的操作只在运行命令时发生一次,同一个实例将被用于执行你的作业,这意味着: 避免在每个作业上启动整个应用程序来节省服务器资源。 在应用程序中所做的任何代码更改后必须手动重启worker。 你也可以这样运行: php artisan queue:work --once 这将启动应用程序的一个实例,处理单个作业,然后干掉脚本。 php artisan queue:listen queue:listen 命令相当于无限循环地运行 queue:work --once 命令,这将导致以下问题: 每个循环都会启动一个应用程序实例。 分配的worker将选择一个工作并执行。 worker进程将被干掉。 使用 queue:listen 确保为每个作业创建一个新的应用程序实例,这意味着代码更改以后不必手动重启worker,同时也意味着将消耗更多的服务器资源。 queue:work 命令 我们来看看 Queue\Console\WorkCommand 类的 handle() 方法,这是当你运行 php artisan queue:work 时会执行的方法: public function handle() { if ($this->downForMaintenance() && $this->option('once')) { return $this->worker->sleep($this->option('sleep')); } $this->listenForEvents(); $connection = $this->argument('connection') ?: $this->laravel['config']['queue.default']; $queue = $this->getQueue($connection); $this->runWorker( $connection, $queue ); } 首先,我们检查应用程序是否处于维护模式,并使用 --once 选项,在这种情况下,我们希望脚本正常运行,因此我们不执行任何作业,我们只需要在完全杀死脚本前让worker在一段时间内休眠。

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接 https://divinglaravel.com/task-scheduling/preventing-overlapping 有时一个预定的工作需要比我们最初预期的更多的时间运行,这样会导致另外一个工作的实例开始,而第一个还没有完成,例如,我们运行一个每分钟生成报告的工作有时候当数据变大时,报表生成可能需要1分钟以上,这样就可以在第一个还在进行时启动该作业的另一个实例。 在大多数情况下,这是很好的,但有时候应该防止这种情况,以保证正确的数据或防止高的服务器资源消耗,所以让我们看看如何防止这种情况在laravel中发生: $schedule->command('mail:send')->withoutOverlapping(); Laravel将检查 Console\Scheduling\Event::withoutOverlapping 类属性,如果设置为true,它将尝试为作业创建互斥,并且只有在创建互斥的情况下才能运行该作业。 但是上面是互斥? 这是我可以在网上找到最有趣的解释: 当我在工作中进行热烈的讨论时,我使用一只橡胶鸡,我在这样的场合放在桌子上。 持有鸡的人是唯一被允许谈话的人。 如果你不握鸡,你不会说话。 你只能指示你想要鸡,等到你说话之前才能得到它。 一旦你完成演讲,你可以将鸡回到主持人,他将把它交给下一个人说话。 这样可以确保人们互不说话,也有自己的空间。 用线替换鸡与互斥和人,你基本上有一个互斥的概念。 – https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558 所以当作业第一次启动时,Laravel创建一个互斥,然后每次作业运行时,它检查互斥是否存在,只有在没有工作的情况下运行。 这里是 withoutOverlapping 方法中做的事 public function withoutOverlapping() { $this->withoutOverlapping = true; return $this->then(function () { $this->mutex->forget($this); })->skip(function () { return $this->mutex->exists($this); }); } 因此,Laravel创建一个filter-callback方法,指示Schedule Manager忽略任务,如果互斥仍然存在,它还会创建一个在完成任务实例后清除互斥的回调。 在运行该作业之前,Laravel会在Console\Scheduling\Event::run()方法中进行以下检查: if ($this->withoutOverlapping && ! $this->mutex->create($this)) { return; } 互斥体属性来自哪里? 当 Console\Scheduling\Schedule 的实例被实例化时,laravel会检查 Console\Scheduling\Mutex 接口的实现是否绑定到容器,如果是,则使用该实例,如果不是,使用Console\Scheduling\CacheMutex实例: $this->mutex = $container->bound(Mutex::class) ?

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接 https://divinglaravel.com/task-scheduling/building-and-running-the-os-command 在启动计划任务的事件的时候,Laravel的进度管理器在Illuminate\Console\Scheduling\Event对象上调用 run() 方法,表示该事件发生在 Illuminate\Console\Scheduling\ScheduleRunCommand 内。 这个 run() 方法构建命令语法,并使用Symfony Process组件在操作系统上运行它,但在构建命令之前,它首先检查该命令是否应该在后台运行,默认情况下所有命令都在前台运行 除非你使用以下方法来调度命令: ->runInBackground() 什么时候我需要在后台运行命令? 假设如果您有几个任务应该同时运行,比如每个小时,Laravel默认设置会指示操作系统逐个运行命令: ~ php artisan update:coupons # Waiting for the command to finish # ... # Command finished, now we run the next one ~ php artisan send:mail 但是,你可以指示操作系统在后台运行命令,以便您可以继续推送更多命令,即使其他命令尚未完成: ~ php artisan update:coupons & ~ php artisan send:mail & 使用命令末尾的&符号可以继续推送命令,而无需等待初始化完成。 run() 方法检查 runInBackground 属性的值,并决定下一个调用哪个方法runCommandInForeground() 还是 runCommandInBackground()。 如果命令要在前台运行,其余部分就简单了: $this->callBeforeCallbacks($container); (new Process( $this->buildCommand(), base_path(), null, null, null ))->run(); $this->callAfterCallbacks($container); Laravel执行任意before-callbacks,将命令发送到OS,最后执行任意before-callbacks。

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接 https://divinglaravel.com/task-scheduling/properties-of-an-event 你添加的每个记录都将转换为 Illuminate\Console\Scheduling\Event 的实例,并存储在Scheduler的 $events 类属性中,Event对象由以下内容组成: 命令运行 CRON表达式 用于评估时间的时区 操作系统运行该命令的用户 命令应该运行的环境列表 维护模式配置 事件重叠配置 命令前台/后台运行配置 用于决定该命令是否运行的检查列表 如何处理输出的配置 命令运行后运行的回调 在命令运行前运行的回调 命令说明 命令的唯一Mutex 命令可能像下面一种方式运行: 回调 在操作系统上运行的命令 artisan命令 被调度的作业 使用回调 在回调的情况下,Container::call() 方法用于运行我们传递的值,这意味着我们可以传递一个可以调用或表示方法的字符串: protected function schedule(Schedule $schedule) { $schedule->call(function () { DB::table('recent_users')->delete(); })->daily(); } Or: protected function schedule(Schedule $schedule) { $schedule->call('MetricsRepository@cleanRecentUsers')->daily(); } 调用操作系统的命令 如果要运行操作系统的命令,可以使用 exec(): $schedule->exec('php /home/sendmail.php --user=10 --attachInvoice')->monthly(); 您还可以将数组作为参数: $schedule->exec('php /home/sendmail.php', [ '--user=10', '--subject' => 'Reminder', '--attachInvoice' ])->monthly(); 调用一个artisan命令 $schedule->command('mail:send --user=10')->monthly(); 你也可以传一个类名

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接 https://divinglaravel.com/task-scheduling/before-the-dive 想象这种情况,作为一个大型SaaS的开发者,您需要找到一种在周末每分钟选择10个随机客户的方式,并提供折扣升级,发送折扣的工作可能非常简单,但我们需要每分钟运行一次,为此我分享一些CRON的简要介绍给还不熟悉人。 CRON CRON是一个守护进程,它驻留在你的linux服务器中,大部分时间都没有唤醒,但是每一分钟它都会睁开双眼,看看是否运行任何给定的任务,你使用crontab文件与该守护进程通信,在大多数常见的设置文件可以位于/etc/crontab,crontab文件可能看起来像这样: 0 0 1 * * /home/full-backup 0 0 * * * /home/partial-backup 30 5 10 * * /home/check-subscriptions 在crontab文件中,每行表示一个计划任务作业,每个作业定义包含两部分: *****部分代表该作业运行的计时器。 第二部分是应运行的命令 CRON时序语法 5个星号按顺序排列如下: 一小时内的分钟 一天内的小时 一个月内的日期 一年内的月份 一周的内的天 示例: 0 0 1 * * 在第一个例子中,表示该工作应在每月,每个月的第一个天,上午12点,每小时第一分钟运行。 或者简单地说,它应该在每月的第一天上午12:00运行。 0 * * * * 在第二个例子中,表示该工作应该每小时运行一次。 30 5 10 * * 表示该工作应该在每个月10日上午5:30运行 这里还有一些其他的示例: * * * * 3 表示工作应该在星期三每分钟运行一次。 * * * * 1-5 表示该工作应该每周一至周五运行。 0 1,15 * * * 表示该工作应该每天在凌晨1点和3点运行两次。 */10 * * * * 表示该工作应该每10分钟运行一次。 所以我们为我们的工作注册一个cron任务? 是的,我们可以在我们的crontab文件中注册:

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接https://divinglaravel.com/queue-system/pushing-jobs-to-queue 有几种方法可以将作业推送到队列中: Queue::push(new InvoiceEmail($order)); Bus::dispatch(new InvoiceEmail($order)); dispatch(new InvoiceEmail($order)); (new InvoiceEmail($order))->dispatch(); 调用Queue facade是对应用程序使用的队列驱动的调用,如果你使用数据库队列驱动,调用push方法是调用Queue\DatabaseQueue类的push方法。 有几种有用的方法可以使用: // 将作业推送到特定的队列 Queue::pushOn('emails', new InvoiceEmail($order)); // 在给定的秒数之后推送作业 Queue::later(60, new InvoiceEmail($order)); // 延迟后将作业推送到特定的队列 Queue::laterOn('emails', 60, new InvoiceEmail($order)); // 推送多个作业 Queue::bulk([ new InvoiceEmail($order), new ThankYouEmail($order) ]); // 推送特定队列上的多个作业 Queue::bulk([ new InvoiceEmail($order), new ThankYouEmail($order) ], null, 'emails'); 调用这些方法之后,所选择的队列驱动会将给定的信息存储在存储空间中,供workers按需获取。 使用命令总线 使用命令总线调度作业进行排队可以给你额外控制权; 您可以从作业类中设置选定的connection, queue, and delay 来决定命令是否应该排队或立即运行,在运行之前通过管道发送作业,实际上你甚至可以从你的作业类中处理整个队列过程。 Bug facade代理到Contracts\Bus\Dispatcher 容器别名,此别名解析为Bus\Dispatcher内的Bus\BusServiceProvider的一个实例: $this->app->singleton(Dispatcher::class, function ($app) { return new Dispatcher($app, function ($connection = null) use ($app) { return $app[QueueFactoryContract::class]->connection($connection); }); }); 所以Bus::dispatch() 调用的 dispatch() 方法是 Bus\Dispatcher 类的:

阅读全文

原文链接https://divinglaravel.com/queue-system/preparing-jobs-for-queue Every job we push to queue is stored in some storage space sorted by the order of execution, this storage place could be a MySQL database, Redis store, or a 3rd party service like Amazon SQS. 我们推送到队列的每个作业都存储在按执行顺序排序的某些存储空间中,该存储位置可以是MySQL数据库,Redis存储或像Amazon SQS这样的第三方服务。 Later in this dive we’re going to explore how workers fetch these jobs and start executing them, but before that let’s see how we store our jobs, here are the attributes we keep for every job we store:

阅读全文

译文GitHub https://github.com/yuansir/diving-laravel-zh 原文链接https://divinglaravel.com/queue-system/before-the-dive Laravel接收请求,做一些工作,然后向用户返回响应,这是处理请求的Web服务器的正常同步工作流程,但有时您需要在后台执行不中断或减慢的一些流程,例如在订单之后向用户发送发票电子邮件,你不想让用户等待邮件服务器接收请求,构建电子邮件消息,然后分派给用户,你只要向屏幕发送“谢谢!”给用户,电子邮件在后台准备和发送,他继续做他自己的事。 Laravel配有内置的队列系统,可帮助您在后台运行任务,并通过简单的API来配置系统在不同情况下起作用。 您可以在 config/queue.php中管理队列配置,默认情况下它有使用不同队列驱动的几个连接,您可以看到项目中可以有多个队列连接,也可以使用多个队列驱动程序。 我们将研究不同的配置,但请先看看API: Queue::push(new SendInvoice($order)); return redirect('thank-you'); 队列Queue facade 是 queue 容器别名,如果我们看看Queue\QueueServiceProvider ,我们可以看到这个别名是如何注册的: protected function registerManager() { $this->app->singleton('queue', function ($app) { return tap(new QueueManager($app), function ($manager) { $this->registerConnectors($manager); }); }); } 所以 Queue facade 代理到在容器中注册为 Queue\QueueManager 类的单例,我们还将连接器注册到Laravel所支持使用的registerConnectors()的不同队列驱动程序中: public function registerConnectors($manager) { foreach (['Null', 'Sync', 'Database', 'Redis', 'Beanstalkd', 'Sqs'] as $connector) { $this->{"register{$connector}Connector"}($manager); } } 该方法只需调用注册 register{DriverName}Connector方法,例如注册一个Redis连接器: protected function registerRedisConnector($manager) { $manager->addConnector('redis', function () { return new RedisConnector($this->app['redis']); }); } addConnector() 方法将值存储到 QueueManager::$connectors 类属性。 连接器只是一个类,它包含一个 connect() 方法,它根据需要创建所需驱动的一个实例,方法看起来像在Queue\Connectors\RedisConnector里面:

阅读全文

Larvae的配置都在config目录下非常方便管理,可以通过config()帮助函数来实现对配置项目的设置和获取,同时用 DotEnv 来实现项目内环境变量的控制,非常强大和方便。我们在日常开发中如果没有使用Laravel框架,比如写一些脚本,或者自己写的项目框架,但是想集成这样的配置管理。这里就讲讲如何集成illuminate/config 到自己的项目中实现Laravel那种config配置。 首先通过composer来安装illuminate/config 和 vlucas/phpdotenv,composer.json如下: { "require": { "illuminate/config": "^5.2", "vlucas/phpdotenv": "^2.3" }, "autoload": { "psr-4": { "App\\": "app/" } } } 创建.env文件,同时创建对应环境的env文件,为了解决不同环境加载不同配置的问题。比如: .env 里面只写入当前环境,比如local,develop , production .local.env 表示本地开发环境的配置项 .develop.env 表示测试环境的配置项 .production 表示生产环境的配置项 关于Laravel在不同环境加载不同配置的方法可以参考我的这篇文章《Laravel在不同的环境调用不同的配置文件》 我们在新建一个配置文件,比如 config/app.php 或者 config/path/to.php 加载配置文件,新建 app/Config.php <?php namespace App; use Illuminate\Config\Repository; use Illuminate\Filesystem\Filesystem; class Config extends Repository { public function loadConfigFiles($path) { $fileSystem = new Filesystem(); if (!

阅读全文

作者的图片

Ryan是菜鸟 | LNMP技术栈笔记

一步一个脚印,一直在路上! LNMP技术栈,web架构学习笔记

菜鸟码农

南京