You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel API中如何使用手机号+OTP替代密码实现用户认证

Laravel 无密码 OTP 认证实现方案

核心问题解答

1. 如何禁用密码字段

不需要做额外的"禁用"操作,按以下步骤调整即可完全绕开密码逻辑:

  • 数据表层面:users表迁移文件中删除password字段,或者设置为->nullable()可选
  • 模型层面:User模型的$fillable属性中移除password字段,也可将password加入$hidden属性避免返回
  • 逻辑层面:认证过程不调用默认带密码校验的方法,完全绕开密码相关逻辑

2. 最优实现方案

核心思路是OTP单独存储、校验通过后手动登录用户,不要依赖Laravel默认的密码校验逻辑:

  • 不要将OTP存在users表中,单独建otps表存储临时OTP记录,包含phone、code、expired_at字段即可,方便过期清理和发送历史追溯
  • OTP校验通过后直接手动登录用户,不需要调用auth()->attempt()方法(该方法默认会校验密码字段)
  • 生成OTP时先判断手机号对应的用户是否存在,不存在再创建,避免同一个手机号重复生成用户

3. 是否可以用OTP字段替代密码完成认证?

不建议这么做,原因如下:

  • OTP是临时有效期凭证,频繁更新users表存储临时数据不合理
  • 无法保留OTP发送和校验历史,也没法处理同一时间多个有效OTP的场景
  • 后续如果需要扩展密码登录、第三方登录等能力,改造成本极高

现有代码问题&优化实现

你当前的代码存在几个明显问题:

  • 每次生成OTP都调用User::create(),同一个手机号多次请求会重复创建用户报错
  • auth()->attempt()只传phone参数会默认校验失败,Laravel该方法默认要求传入password做哈希校验
  • 登录逻辑中$user = new UserResource(User::find($user->id))在$user未定义的情况下调用,会直接报错
  • 生成OTP接口返回OTP明文,生产环境存在严重安全风险

优化后代码

生成OTP方法

public function generateOtp(Request $request)
{
    $request->validate([
        'phone' => 'required|regex:/^1[3-9]\d{9}$/' // 补充手机号格式校验
    ]);

    $otp = new Otp();
    $code = $otp->generate($request->phone, 6, 15);

    // 手机号不存在则创建用户,存在则直接返回
    User::firstOrCreate(
        ['phone' => $request->phone]
        // 其他用户默认字段可补充在第二个参数数组中
    );

    // 补充短信发送逻辑
    return response()->json(['message' => 'OTP已发送至您的手机']); // 生产环境禁止返回OTP明文
}

登录方法

public function login(Request $request)
{
    $validator = Validator::make($request->all(), [
        'phone' => 'required',
        'otp' => 'required|digits:6',
    ]);

    if ($validator->fails()) {
        return response()->json(['success' => false, 'data' => $validator->errors()], 400);
    }

    $otp = new Otp();
    $otpResult = $otp->validate($request->phone, $request->otp);

    if (!$otpResult->status) {
        return response()->json(['code'=>2, 'message'=>'OTP已过期或不正确,请重新获取']);
    }

    // OTP校验通过后直接查询用户,手动登录绕开密码校验
    $user = User::where('phone', $request->phone)->first();
    if (!$user) {
        return ResponseHelper::notSuccessful(1502, '登录凭证错误');
    }

    auth()->login($user);
    $this->revokeTokens($user->id);
    $token = $user->createToken('AccessToken')->accessToken;

    $userResource = new UserResource($user);
    return response()->json([
        'success' => true,
        'code' => 1500,
        'user' => $userResource,
        'token' => $token
    ]);
}

额外注意事项

  • OTP校验成功后要标记为已使用,避免同一个OTP被多次调用登录
  • 生成OTP接口加频率限制,避免被恶意刷短信接口
  • 所有短信下发的OTP不要在接口响应中返回明文

内容的提问来源于stack exchange,提问作者Fateh Alrabeai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:06:02