更新用户时忽略当前用户字段唯一校验及auth获取为空问题
更新当前用户数据时跳过自身字段唯一性校验的实现方法
问题根因
自定义验证器中auth()->id()返回null,是因为你将@guard(with: ["api"])声明在了单个mutation字段上:Lighthouse字段级守卫的执行时机晚于输入验证阶段,验证器运行时认证逻辑还未启动,全局auth上下文未初始化,自然无法获取到登录用户ID。
同时你同时在SDL的Input定义中写了@rules、又编写了自定义验证器类,两套校验规则重复,会产生规则冲突。
具体实现步骤
- 清理重复规则:删除
UpdateUserInput类型中所有字段上的@rules注解,所有校验规则统一在自定义验证器类中维护,避免双重校验。 - 调整更新字段的非空标记:更新场景下通常支持部分字段修改,去掉SDL中字段后的
!非空强制标记,配合验证器的sometimes规则使用,否则不传对应字段会直接被GraphQL层拦截,无法走到自定义验证逻辑:input UpdateUserInput { name: String lastname: String username: String email: String phone: String } - 解决验证器中获取用户ID为空的问题,二选一即可
- 方案一(推荐):调整守卫执行时机
在config/lighthouse.php配置文件中,将默认守卫设置为api,让认证逻辑在请求进入验证流程前就完成初始化:
配置完成后,验证器'guard' => 'api',rules()方法内的auth()->id()就能正常返回当前登录用户ID,你原来写的Rule::unique()->ignore($id)逻辑即可正常生效,自动跳过当前用户自身的唯一校验。 - 方案二:直接从请求上下文取用户
如果不想修改全局守卫配置,可以不依赖auth()助手,直接从Lighthouse注入的请求属性中获取当前用户:public function rules(): array { // 直接从Lighthouse上下文取用户,无需等待全局auth初始化 $userId = request()->attributes->get('lighthouse-user')?->id; return [ 'name' => ['sometimes', 'string', 'between:2,25'], 'lastname' => ['sometimes', 'string', 'between:2,25'], 'username' => [ 'sometimes', 'string', 'between:2,12', // 补全正则结束锚点,避免非法字符绕过校验 'regex:/^[a-zA-Z0-9]+$/', Rule::unique('users', 'username')->ignore($userId), ], 'email' => [ 'sometimes', 'string', 'email', 'max:255', Rule::unique('users', 'email')->ignore($userId), ], 'phone' => [ 'sometimes', // 补全正则起止锚点,避免非10位数字绕过校验 'regex:/^[0-9]{10}$/', Rule::unique('users', 'phone')->ignore($userId), ], ]; }
- 方案一(推荐):调整守卫执行时机
校验规则优化提示
你原来写的正则规则缺少结束锚点,存在校验绕过风险:
- 原username正则
/^[a-zA-Z0-9]+/只校验开头是字母数字,后续加特殊字符也能通过校验 - 原phone正则
/[0-9]{10}/只校验字符串中存在连续10位数字,前后加其他字符、数字长度超过10位都能通过校验
建议按上述代码补全^和$锚点,保证校验准确性。
内容的提问来源于stack exchange,提问作者devmrh
相关产品推荐
相关产品推荐

