在 Laravel 8 里搭建用户系统通常从内置的 Laravel Breeze 或 Jetstream 起步,但这些脚手架默认面向浏览器会话,返回的是重定向而非 JSON。当我们需要为安卓、iOS 或前端框架提供注册接口时,就必须改造控制器与验证逻辑,让邮箱或用户名在数据库中保持唯一,并以统一的 JSON 结构返回结果。

一、路由与守卫配置
Laravel 8 的 auth 路由默认使用 web 中间件和 session 守卫。要返回 JSON,我们应在 routes/api.php 中定义独立路由,并指定 auth 守卫为 api,或者使用默认的 token 驱动。这样请求进入时不会尝试写入会话,更适合无状态客户端。
打开 config/auth.php,确认 providers 中 users 使用的是 eloquent 且模型正确。若计划用 Sanctum 签发令牌,需先安装并发布配置,再将 api 守卫的 driver 设为 sanctum。下面是一段典型的路由声明,它绕开了脚手架自带的注册控制器:
<?php
// routes/api.php
use IlluminateSupportFacadesRoute;
use AppHttpControllersApiRegisterController;
Route::post('/register', [RegisterController::class, 'store']);
二、唯一性验证规则
保证用户唯一的核心在于验证层。Laravel 提供了 Rule::unique 来查询指定表字段是否重复。我们可以在独立的表单请求类里声明,也可以直接在控制器用 Validator 门面。推荐表单请求,因为能让控制器更瘦,且自动返回 422 与 JSON 错误结构。
以下示例创建了一个 RegisterRequest,要求 name、email、password 必填,且 email 在 users 表中唯一。注意当处于更新场景时才需要忽略自身,注册场景不需要 ignore 参数。密码用 confirmed 规则可要求前端传 password_confirmation 字段,若接口不强制则可去掉。
<?php
namespace AppHttpRequests;
use IlluminateFoundationHttpFormRequest;
use IlluminateValidationRule;
class RegisterRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', Rule::unique('users', 'email')],
'password' => ['required', 'string', 'min:8'],
];
}
}
三、控制器返回 JSON
控制器负责接收验证后的数据、创建用户、可选地签发令牌,最后用 response()->json() 封装。很多初学者在这里继续用 redirect(),造成移动端收到 302 且无法解析。我们应当明确设置状态码与数据结构,例如返回 201 及用户对象和 token。
下面代码演示了使用 Hash 加密密码,调用 User 模型的 create 方法,再用 Sanctum 的 createToken 生成明文令牌。如果不用 Sanctum,也可返回 jwt 或单纯 success 消息。注意令牌字段名保持前后端约定一致,避免前端取不到。
<?php
namespace AppHttpControllersApi;
use AppHttpControllersController;
use AppHttpRequestsRegisterRequest;
use AppModelsUser;
use IlluminateSupportFacadesHash;
class RegisterController extends Controller
{
public function store(RegisterRequest $request)
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('mobile-app')->plainTextToken;
return response()->json([
'message' => '注册成功',
'user' => $user,
'token' => $token,
], 201);
}
}
四、常见误区与处理
一个容易被忽略的点是:当验证失败时,Laravel 会自动根据请求头中的 Accept 决定返回格式。如果客户端没发 Accept: application/json,即便在 api 路由下也可能拿到重定向。解决办法是在中间件或 Kernel 里强制 API 响应,或者要求前端必带该头。
另一个坑是唯一索引与并发。Rule::unique 只是查询层校验,高并发时两个相同邮箱可能同时通过验证再写入,此时数据库唯一索引会抛异常。建议在 users 表迁移文件中对 email 加 unique() 修饰,并在控制器用 try-catch 捕获 QueryException,返回友好的 JSON 错误而非 500 页面。
// 迁移文件中确保唯一
Schema::create('users', function ($table) {
$table->id();
$table->string('email')->unique();
$table->timestamps();
});
五、总结
在 Laravel 8 实现唯一用户注册并返回 JSON,关键动作只有三个:用 Rule::unique 做校验、在 api 路由写无状态控制器、用 response()->json 明示输出。配合 Sanctum 或手动令牌,即可让网页与客户端共用一套用户表而互不干扰。
只要避开会话重定向和头协商的陷阱,并补上数据库层唯一索引,这套方案在生产环境足够稳健,也方便后期接入登录、找回密码等其余接口。