validate([ 'response_type' => ['required', 'in:code'], 'client_id' => ['required', 'string'], 'redirect_uri' => ['required', 'string'], 'scope' => ['nullable', 'string'], 'state' => ['required', 'string', 'max:200'], 'nonce' => ['nullable', 'string', 'max:200'], 'code_challenge' => ['required', 'string', 'max:200'], 'code_challenge_method' => ['required', 'in:S256'], 'confirm' => ['nullable'], ]); $client = OauthClient::query()->where('client_id', $data['client_id'])->where('status', 'active')->first(); if (! $client || ! $client->allowsRedirect($data['redirect_uri'])) { abort(400, '客户端或回调地址无效'); } if (! Auth::check()) { $login = rtrim((string) config('qz.frontend_url'), '/').'/login?redirect='.urlencode($request->fullUrl()); return redirect()->away($login); } $user = $request->user(); if ($user->status !== 'active') { return redirect()->away($this->withQuery($data['redirect_uri'], [ 'error' => 'access_denied', 'state' => $data['state'], ])); } $scopes = $this->oauth->scopes($data['scope'] ?? 'openid'); if (! $client->is_first_party && ! $request->boolean('confirm')) { return view('oauth.consent', [ 'client' => $client, 'scopes' => $scopes, 'query' => $request->except(['_token', 'confirm']), ]); } $code = $this->oauth->issueCode($client, $user, $data, $scopes); return redirect()->away($this->withQuery($data['redirect_uri'], [ 'code' => $code, 'state' => $data['state'], ])); } public function token(Request $request) { $client = $this->oauth->clientFromRequest($request); if (! $client) { return response()->json(['error' => 'invalid_client'], 401); } $result = match ($request->input('grant_type')) { 'authorization_code' => $this->oauth->exchange($request, $client), 'refresh_token' => $this->oauth->refresh($request, $client), default => ['error' => 'unsupported_grant_type'], }; $status = isset($result['error']) ? 400 : 200; return response()->json($result, $status); } public function userinfo(Request $request) { $token = $this->bearer($request); $info = $token ? $this->oauth->userinfo($token) : null; if (! $info) { return response()->json(['error' => 'invalid_token'], 401); } return response()->json($info); } public function introspect(Request $request) { $client = $this->oauth->clientFromRequest($request); if (! $client) { return response()->json(['active' => false], 401); } return response()->json($this->oauth->introspect((string) $request->input('token'))); } public function revoke(Request $request) { $client = $this->oauth->clientFromRequest($request); if (! $client) { return response()->json(['error' => 'invalid_client'], 401); } $this->oauth->revoke((string) $request->input('token')); return response()->noContent(); } private function bearer(Request $request): ?string { $header = (string) $request->header('Authorization'); if (! str_starts_with($header, 'Bearer ')) { return null; } return trim(substr($header, 7)); } private function withQuery(string $uri, array $params): string { $joiner = str_contains($uri, '?') ? '&' : '?'; return $uri.$joiner.http_build_query($params); } }