Laravel 8 如何验证用户登录时的子地点访问权限
Laravel 8 基于子地点的登录验证实现
方案一:自定义验证规则
1. 创建自定义验证规则
执行Artisan命令生成规则文件:
php artisan make:rule ValidSubLocation
2. 编写验证逻辑
打开app/Rules/ValidSubLocation.php,修改passes方法实现子地点权限验证:
<?php namespace App\Rules; use Illuminate\Contracts\Validation\Rule; use Illuminate\Support\Facades\DB; class ValidSubLocation implements Rule { protected $userId; public function __construct($userId) { $this->userId = $userId; } public function passes($attribute, $value) { // 校验用户对应的子地点是否存在且处于启用状态 return DB::table('user_locations') ->where('user_id', $this->userId) ->where('sub_location_id', $value) ->where('status', 'Y') ->exists(); } public function message() { return '您无权访问该子地点,或该子地点已被禁用。'; } }
3. 在登录请求中绑定规则
创建登录请求类:
php artisan make:request LoginRequest
打开app/Http/Requests/LoginRequest.php,配置验证规则和错误提示:
<?php namespace App\Http\Requests; use App\Rules\ValidSubLocation; use Illuminate\Foundation\Http\FormRequest; class LoginRequest extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'user_id' => 'required|exists:users,user_id,status,Y', 'password' => 'required', 'sub_location_id' => ['required', new ValidSubLocation($this->user_id)], ]; } public function messages() { return [ 'user_id.exists' => '该用户不存在或已被禁用', 'password.required' => '请输入密码', 'sub_location_id.required' => '请选择子地点', ]; } }
4. 控制器处理登录逻辑
修改LoginController的login方法,使用自定义请求完成验证:
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Http\Requests\LoginRequest; use Illuminate\Support\Facades\Auth; class LoginController extends Controller { public function login(LoginRequest $request) { // 验证用户密码 if (!Auth::attempt(['user_id' => $request->user_id, 'password' => $request->password])) { return back()->withErrors([ 'password' => '密码错误', ])->withInput(); } // 将子地点ID存入session,方便后续业务权限控制 session(['sub_location_id' => $request->sub_location_id]); return redirect()->intended('/dashboard'); } }
方案二:直接在控制器内完成所有验证
如果不需要复用验证规则,可直接在控制器中整合所有校验逻辑:
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; class LoginController extends Controller { public function login(Request $request) { // 基础字段验证 $request->validate([ 'user_id' => 'required|exists:users,user_id,status,Y', 'password' => 'required', 'sub_location_id' => 'required', ], [ 'user_id.exists' => '该用户不存在或已被禁用', 'password.required' => '请输入密码', 'sub_location_id.required' => '请选择子地点', ]); // 校验子地点权限 $hasValidSubLocation = DB::table('user_locations') ->where('user_id', $request->user_id) ->where('sub_location_id', $request->sub_location_id) ->where('status', 'Y') ->exists(); if (!$hasValidSubLocation) { return back()->withErrors([ 'sub_location_id' => '您无权访问该子地点,或该子地点已被禁用。', ])->withInput(); } // 验证密码正确性 if (!Auth::attempt(['user_id' => $request->user_id, 'password' => $request->password])) { return back()->withErrors([ 'password' => '密码错误', ])->withInput(); } // 存储子地点信息到session session(['sub_location_id' => $request->sub_location_id]); return redirect()->intended('/dashboard'); } }
额外优化建议
- 给
User模型和UserLocation模型建立关联,方便后续业务调用:
在app/Models/User.php中添加:public function userLocations() { return $this->hasMany(UserLocation::class, 'user_id'); } - 登录成功后存入session的
sub_location_id,可在后续中间件中校验,确保用户所有请求都限定在该子地点范围内。
内容的提问来源于stack exchange,提问作者Lokesh M
相关产品推荐
相关产品推荐

