Laravel 8.x用户注册时如何为每位用户生成自定义随机密钥
无Passport依赖的用户专属密钥生成实现
现有代码的几个明显问题
- 密钥无法持久化:计算得到的哈希值仅给已创建的
$user实例临时赋值,既没有在User::create的入参中纳入该字段,也没有调用$user->save()执行保存,数据库永远不会存储这个密钥值 - 接口返回空值:原代码里的
$token是Passport生成的变量,对应生成逻辑已经被注释,接口返回这个未定义变量会直接触发PHP报错 - 逻辑顺序错位:先创建用户、再临时修改实例属性的写法没有任何持久化效果,生成的密钥完全白做
实现思路
完全不需要依赖Passport,自定义密钥的逻辑和Laravel自带的密码存储逻辑完全一致:
- 注册时生成高熵随机字符串作为用户的专属明文密钥
- 对明文密钥做不可逆哈希计算,把哈希值存到数据库的
user_secret_key字段(字段长度设为64位,刚好匹配sha256的输出长度) - 首次注册时把明文密钥返回给用户,提示用户自行保存(因为哈希不可逆,后续无法从数据库还原出明文)
- 后续接口鉴权时,拿到用户传过来的明文密钥,做同样的sha256哈希计算,和数据库存储的字段做等值匹配,匹配成功即验证通过
修正后的可运行代码
public function register(Request $request) { // 放开参数校验,过滤非法输入 $validated = $request->validate([ 'username' => 'required', 'phonenumber' => 'required|digits:10|unique:users', 'password' => 'required|string', 'device_serial_number' => 'required' ]); // 生成60位长度的随机明文密钥,熵值足够抵抗暴力破解 $plainSecret = Str::random(60); // 计算哈希值,仅将哈希值存入数据库 $hashedSecret = hash('sha256', $plainSecret); $user = User::create([ 'username' => $validated['username'], 'phonenumber' => $validated['phonenumber'], 'device_serial_number' => $validated['device_serial_number'], 'password' => bcrypt($validated['password']), 'user_secret_key' => $hashedSecret ]); if ($user) { // 首次注册返回明文密钥,后续不再向用户返回该值 return response()->json([ 'secret_key' => $plainSecret, 'user_id' => $user->id ], 201); } return response()->json(['error' => '注册流程异常'], 500); }
落地注意事项
- 绝对不要在数据库存储明文密钥,存储哈希的逻辑和存密码的要求一致,就算数据库被拖库,攻击者也无法拿到可直接使用的用户密钥
- 鉴权时的哈希计算逻辑必须和注册时完全一致,否则会出现密钥匹配失败的问题
- 用户如果需要重置密钥,可直接复用重置密码的流程:生成新的明密文对,替换数据库里的哈希值,把新的明文返回给用户即可
内容的提问来源于stack exchange,提问作者user15205644
相关产品推荐
相关产品推荐

