Laravel项目中Passport OAuth2角色及Web端调用自身API疑问
Hey there! Let's break this down clearly—OAuth2 terminology can feel overwhelming at first, but once you map the roles to your Laravel project, it all clicks. Then we'll cover exactly how to make your web app call its own RESTful API using Passport.
First: Mapping OAuth2 Roles to Your Project
Let's translate each OAuth2 role directly to what they are in your setup:
- Resource Owner: This is your end user—whether they're logging into your web app or future mobile app. They own the protected data (like their profile, order history, etc.) and are the ones who grant permission for apps to access that data.
- Resource Server: This is your Laravel app's RESTful API layer. It's the part that holds and serves the protected resources, and it validates incoming API requests to make sure only authorized clients/users can access the data.
- Client: These are the apps requesting access to the resource server. In your case, there are two clients:
- Your existing Laravel web application
- The native mobile app you plan to build later
Both act as "clients" that need authorization to call your API.
- Authorization Server: This is Laravel Passport itself. It handles all the heavy lifting of verifying client identities, processing user authorization requests, and issuing access tokens that clients can use to access the resource server.
Second: How to Make Your Web App Call Its Own API
There are a couple of solid approaches here, depending on how strictly you want to follow OAuth2 best practices:
Option 1: Use Passport's Password Grant (OAuth2 Compliant)
Since your web app is a trusted first-party client, the Password Grant flow works perfectly. Here's how to implement it:
Create a Password Grant Client
Run this Artisan command in your terminal to generate the client credentials:php artisan passport:client --passwordSave the generated
client_idandclient_secret—you'll need these in your.envfile:PASSPORT_PASSWORD_CLIENT_ID=your-client-id PASSPORT_PASSWORD_CLIENT_SECRET=your-client-secretFetch a Token When the User Logs In
Modify your web app's login logic to retrieve an access token after the user successfully authenticates. For example, in yourLoginController:use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Auth; public function login(Request $request) { // Validate user credentials first $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); if (!Auth::attempt($request->only('email', 'password'))) { return back()->withErrors(['email' => 'Invalid credentials']); } // Request access token from Passport $tokenResponse = 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' => '', // Leave empty unless you need scoped permissions ]); // Store the token in the user's session session(['api_access_token' => $tokenResponse->json()['access_token']]); return redirect()->intended('/dashboard'); }Use the Token for API Requests
Whenever your web app needs to call the API, attach the token to the request headers. Using Laravel'sHttpclient:use Illuminate\Support\Facades\Http; $userData = Http::withToken(session('api_access_token')) ->get('/api/user') ->json();Or if you're using frontend JavaScript (like Axios):
axios.get('/api/user', { headers: { 'Authorization': `Bearer ${sessionStorage.getItem('api_access_token')}` } });
Option 2: Share Web Authentication with the API (Simpler, Less Strict)
If you want to skip the OAuth2 token flow for your web app, you can create a custom middleware that lets authenticated web users access the API without a token. Here's how:
Create a Custom Middleware
Generate a new middleware with Artisan:php artisan make:middleware ApiWebAuthUpdate the middleware to sync the web-authenticated user with the API guard:
namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Auth; class ApiWebAuth { public function handle($request, Closure $next) { // If the user is logged in via web, set them as the API user if (Auth::guard('web')->check()) { Auth::guard('api')->setUser(Auth::guard('web')->user()); } return $next($request); } }Register the Middleware
Add it to the$routeMiddlewarearray inapp/Http/Kernel.php:protected $routeMiddleware = [ // ... existing middleware 'api.web.auth' => \App\Http\Middleware\ApiWebAuth::class, ];Apply the Middleware to API Routes
In yourroutes/api.php, use this middleware alongside the defaultauth:apimiddleware:Route::middleware(['api.web.auth', 'auth:api'])->group(function () { Route::get('/user', function (Request $request) { return $request->user(); }); // Add your other API routes here });Now, any user logged into your web app can access these API routes directly without needing to send an access token.
Which Option Should You Choose?
- Go with Option 1 if you want to strictly follow OAuth2 standards, keep a consistent flow between web and mobile apps, and benefit from token expiration/security features.
- Go with Option 2 if you want a simpler setup for your web app and don't mind deviating slightly from the OAuth2 flow (since it's a trusted first-party client).
内容的提问来源于stack exchange,提问作者rakk92

