Skip to main content

Jetstream 开箱即用的用户功能

官网:https://jetstream.laravel.com/

官方 GitHub 能看到基本保持一天一更新,绝对比自己重新写 User 服务更下合适。

前端必然选 Inertia + Vue 的方案,灵活性更强。 但要注意 Inertia 是每一个页都实例化一次 Vue,每个 view 是一个独立的单页应用。 不是整个项目一个单页应用,必须注意。 2022年 Inertia 已经支持 服务端渲染,但是不完善,继续观望。

安装

先装 Laravel 再装 Jetstream,注意两者的版本关系要匹配。 安装 Jetstream 要新项目干净的 Laravel,相当于只有一次机会装,因此尽量都装最新版。

为了对未来重装、升级、迁移用户服务保持最大程度的灵活性,一个原则:尽量不二次修改 Jetstream 的功能,即:只新增自己的文件、不修改 Jetstream 自带的文件,当然,配置相关文件除外。

Laravel 安装:https://laravel.com/docs/ composer create-project laravel/laravel example-app

Jetstream 安装:https://jetstream.laravel.com/2.x/installation.html composer require laravel/jetstream

安装成功后,立即 git commit 一次方便回退。

快速跑起项目

用 PHP 的 Web Server。

sudo php -S localhost:80 -t public/

自定义身份验证逻辑

一定要仔细阅读文档,参透其中的规则。

参考:

在身份验证成功(登录成功)后添加自定义逻辑

身份验证成功后会进入 redirect 重定向环节,所以代码逻辑加在这里。

参考:https://laravel.com/docs/9.x/fortify#customizing-authentication-redirects

后端代理记得要将真实 host 转发给 Jetstream

前端 js 需要用到路由表,方法是通过 Tightenco\Ziggy\BladeRouteGenerator 将 Blade 模板内的 @routes 预先生成 js 语法的 ziggy 配置:const Ziggy = { url: "...", // skip...}。 默认的应用入口模板是:resources/views/app.blade.php

Ziggy 是根据 php 动态取得的 host 来生成路由的 url 前缀。并不是用 .env 文件里面的 APP_URL 配置项。不管当时作者是处于什么原因没有读全局应用配置,但这在后端代理转发时,可能会遇到问题。

这里假设 Jetstream 运行在 localhost:8080 如果后端代理没有转发 xxx.abc.com ,那么得到的 Ziggy 配置是:{ url: 'http://localhost/' },这显然是不符合预期的。

解决方法是 Nginx 配置要加上:proxy_set_header Host $http_host;

Nginx 配置示例:

server {
listen 80;
server_name 'xxx.abc.com';

location / {
proxy_pass http://localhost:8080/;
proxy_set_header Host $http_host;
}
}

经过测试发现,php artisan ziggy:generate 生成的 resources/js/ziggy.js 里面的 url 又是正确读取 .env 的 APP_URL 配置。 在生产环境为了性能优化,将 ziggy.js 配置预先生成好给前端用户,减少网络请求和网络带宽。

自定义 Logout 逻辑

Logout 用的是 Fortify。

通过逆向查找,可知 Fortify 的路由定义在 vendor/laravel/fortify/routes/routes.php 里面:

Route::group(['middleware' => config('fortify.middleware', ['web'])], function () {
Route::post('/logout', [AuthenticatedSessionController::class, 'destroy'])
->name('logout');
});

登出的代码逻辑在 vendor/laravel/fortify/src/Http/Controllers/AuthenticatedSessionController.phpdestory 方法里:

    /**
* Destroy an authenticated session.
*
* @param \Illuminate\Http\Request $request
* @return \Laravel\Fortify\Contracts\LogoutResponse
*/
public function destroy(Request $request): LogoutResponse
{
$this->guard->logout();

$request->session()->invalidate();

$request->session()->regenerateToken();

return app(LogoutResponse::class);
}

参考着上面的路由及控制器方法,可以着手自定义了。

例如自定义 Logout 逻辑:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Laravel\Fortify\Http\Controllers\AuthenticatedSessionController as Controller;
use Laravel\Fortify\Contracts\LogoutResponse;

class AuthenticatedSessionController extends Controller
{
public function destroy(Request $request): LogoutResponse
{
// TODO 自定义 Logout 前要做什么事情
return parent::destroy($request);
}
}