Files
qztool/backend/app/Http/Controllers/OauthController.php
T

124 lines
4.1 KiB
PHP
Raw Normal View History

<?php
namespace App\Http\Controllers;
use App\Models\OauthClient;
use App\Services\OAuthService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class OauthController extends Controller
{
public function __construct(private readonly OAuthService $oauth) {}
public function authorize(Request $request)
{
$data = $request->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);
}
}