Lumen使用Tymon JWT库,通过非账号密码字段验证生成令牌
用Tymon JWT实现自定义字段(ID/Mobile/OTP)验证并生成令牌
没问题,我来帮你实现这个需求——跳过默认的邮箱密码验证,用id、mobile和otp三个字段匹配用户后,通过Tymon JWT库生成有效令牌。以下是具体实现步骤:
1. 确保User模型实现JWTSubject接口
Tymon JWT需要从用户模型获取唯一标识和自定义声明,所以你的User模型必须实现JWTSubject接口:
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { // 你的模型属性、关联等代码... // 返回用户唯一标识(通常是主键ID) public function getJWTIdentifier() { return $this->getKey(); } // 返回自定义JWT声明(可以添加你需要的字段,比如mobile) public function getJWTCustomClaims() { return [ 'mobile' => $this->mobile, 'user_id' => $this->id ]; } }
2. 编写自定义登录验证逻辑
创建一个控制器方法,处理前端传来的id、mobile、otp参数,验证匹配后生成令牌:
namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Models\User; use Illuminate\Http\Request; use Tymon\JWTAuth\Facades\JWTAuth; use Illuminate\Support\Facades\Validator; class OtpLoginController extends Controller { public function authenticate(Request $request) { // 第一步:验证请求参数的合法性 $validator = Validator::make($request->all(), [ 'id' => 'required|integer', 'mobile' => 'required|string', 'otp' => 'required|string', ]); if ($validator->fails()) { return response()->json(['errors' => $validator->errors()], 400); } // 第二步:查询匹配的用户记录 $user = User::where([ 'id' => $request->id, 'mobile' => $request->mobile, 'otp' => $request->otp, ])->first(); // 如果没有找到匹配用户,返回认证失败 if (!$user) { return response()->json(['error' => 'Invalid credentials'], 401); } // 第三步:生成JWT令牌(可以额外添加自定义声明) $token = JWTAuth::fromUser($user, [ 'additional_claim' => 'your_custom_value' // 可选:添加更多自定义字段 ]); // 第四步:返回令牌及相关信息 return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth()->factory()->getTTL() * 60, // 令牌过期时间(秒) 'user' => $user->only(['id', 'mobile']) // 返回需要的用户信息 ]); } }
3. (可选)配置自定义认证守卫
如果想让逻辑更规范,可以在config/auth.php中配置一个自定义的JWT守卫:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'jwt', 'provider' => 'users', ], // 添加自定义守卫 'otp-api' => [ 'driver' => 'jwt', 'provider' => 'users', ], ],
之后在控制器中可以用这个守卫来生成令牌,效果和JWTAuth::fromUser()一致:
$token = auth('otp-api')->login($user);
4. 安全建议
- 验证成功后立即失效当前OTP:比如更新用户表的
otp字段为null,或者添加otp_expired_at字段标记过期时间,避免OTP被重复使用。 - 限制OTP的有效时间:在生成OTP时就设置过期时间,查询时同时验证
otp_expired_at > now()。
内容的提问来源于stack exchange,提问作者user254153
相关产品推荐
相关产品推荐

