Laravel 9健身APP API:管理员与用户角色登录认证故障排查
问题根源分析
你的错误核心在于对Laravel Passport的认证逻辑理解有误:
Auth::attempt()是**SessionGuard(web认证守卫)**的方法,用于基于会话的登录,而Passport的TokenGuard(api认证守卫)并不支持该方法,因此抛出「Method ... does not exist」异常。Auth::guard('api')返回的是TokenGuard实例对象,你直接加括号调用(当作函数),自然会触发「Object ... is not callable」错误。
解决方案
一、先确认Passport基础配置正确
确保你已经完成Passport的初始化:
- 安装Passport并执行迁移:
composer require laravel/passport php artisan migrate php artisan passport:install
- 修改
config/auth.php,将api守卫的driver设为passport:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ],
- 在User模型中引入Passport的
HasApiTokenstrait:
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Passport\HasApiTokens; class User extends Authenticatable { use HasApiTokens, Notifiable; // ... 其他模型代码 }
二、登录控制器的正确写法(两种可选方案)
方案1:使用Passport密码授权客户端(符合OAuth2标准,推荐)
- 生成密码授权客户端,记录生成的
client_id和client_secret:
php artisan passport:client --password
- 在
.env文件中添加客户端信息:
PASSPORT_PASSWORD_CLIENT_ID=你的客户端ID PASSPORT_PASSWORD_CLIENT_SECRET=你的客户端密钥
- 登录控制器代码:
namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Http; class LoginController extends Controller { public function login(Request $request) { $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); // 调用Passport内置的密码授权端点获取令牌 $response = Http::asForm()->post(config('app.url').'/oauth/token', [ 'grant_type' => 'password', 'client_id' => env('PASSPORT_PASSWORD_CLIENT_ID'), 'client_secret' => env('PASSPORT_PASSWORD_CLIENT_SECRET'), 'username' => $request->email, 'password' => $request->password, 'scope' => '', // 可根据需求设置权限范围 ]); if ($response->failed()) { return response()->json(['message' => '邮箱或密码错误'], 401); } return $response->json(); } }
方案2:手动验证凭证并生成令牌(适合简单场景)
直接验证用户密码,手动创建个人访问令牌:
namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Models\User; class LoginController extends Controller { public function login(Request $request) { $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); $user = User::where('email', $request->email)->first(); // 验证密码是否匹配 if (!$user || !password_verify($request->password, $user->password)) { return response()->json(['message' => '邮箱或密码错误'], 401); } // 生成API访问令牌 $token = $user->createToken('健身APP API令牌')->accessToken; return response()->json([ 'token' => $token, 'user' => $user, 'role' => $user->role, // 假设用户表有role字段区分管理员/普通用户 ]); } }
三、AdminMiddleware的正确实现与使用
- 中间件代码(假设用户表用
role字段标识角色,管理员值为admin):
namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class AdminMiddleware { public function handle(Request $request, Closure $next) { // 先验证用户已通过API认证 if (!Auth::guard('api')->check()) { return response()->json(['message' => '未授权访问'], 401); } $user = Auth::guard('api')->user(); // 校验用户角色是否为管理员 if ($user->role !== 'admin') { return response()->json(['message' => '无权限访问该资源'], 403); } return $next($request); } }
- 在
app/Http/Kernel.php中注册中间件:
protected $routeMiddleware = [ // ... 其他中间件 'admin' => \App\Http\Middleware\AdminMiddleware::class, ];
- 路由中使用中间件:
use Illuminate\Support\Facades\Route; // 登录路由(无需认证) Route::post('/login', [\App\Http\Controllers\Auth\LoginController::class, 'login']); // 管理员专属路由组 Route::middleware(['auth:api', 'admin'])->group(function () { Route::get('/admin/dashboard', function () { return response()->json(['message' => '管理员面板']); }); // 其他管理员路由... }); // 普通用户路由组 Route::middleware('auth:api')->group(function () { Route::get('/user/profile', function () { return response()->json(Auth::user()); }); // 其他用户路由... });
内容的提问来源于stack exchange,提问作者Black Fecta
相关产品推荐
相关产品推荐

