oauth providers

This commit is contained in:
xiaomlove
2025-04-24 15:30:07 +07:00
parent 13bc885fd7
commit b3aeaf04b4
18 changed files with 310 additions and 35 deletions
@@ -0,0 +1,123 @@
<?php
namespace App\Filament\Resources\Oauth;
use App\Filament\Resources\Oauth\ProviderResource\Pages;
use App\Filament\Resources\Oauth\ProviderResource\RelationManagers;
use App\Models\OauthProvider;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ProviderResource extends Resource
{
protected static ?string $model = OauthProvider::class;
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
protected static ?string $navigationGroup = 'Oauth';
protected static ?int $navigationSort = 5;
public static function getNavigationLabel(): string
{
return __('admin.sidebar.oauth_provider');
}
public static function getBreadcrumb(): string
{
return self::getNavigationLabel();
}
public static function form(Form $form): Form
{
return $form
->schema([
Forms\Components\TextInput::make('name')
->label(__('label.name'))
->required()
,
Forms\Components\TextInput::make('client_id')
->label(__('oauth.client_id'))
->required()
,
Forms\Components\TextInput::make('client_secret')
->label(__('oauth.secret'))
->required()
,
Forms\Components\TextInput::make('authorization_endpoint_url')
->label(__('oauth.authorization_endpoint_url'))
->required()
,
Forms\Components\TextInput::make('token_endpoint_url')
->label(__('oauth.token_endpoint_url'))
->required()
,
Forms\Components\TextInput::make('user_info_endpoint_url')
->label(__('oauth.user_info_endpoint_url'))
->required()
,
Forms\Components\TextInput::make('id_claim')
->label(__('oauth.id_claim'))
->required()
,
Forms\Components\TextInput::make('username_claim')
->label(__('oauth.username_claim'))
,
Forms\Components\TextInput::make('email_claim')
->label(__('oauth.email_claim'))
,
Forms\Components\TextInput::make('priority')
->label(__('label.priority'))
->default(0)
->numeric()
->helperText(__('label.priority_help'))
,
Forms\Components\Toggle::make('enabled')
->label(__('label.enabled'))
,
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('id'),
Tables\Columns\TextColumn::make('client_id')->label(__('oauth.client_id')),
Tables\Columns\TextColumn::make('client_secret')->label(__('oauth.secret')),
Tables\Columns\TextColumn::make('authorization_endpoint_url')->label(__('oauth.authorization_endpoint_url')),
Tables\Columns\TextColumn::make('uuid')
->label(__('oauth.redirect'))
->formatStateUsing(fn ($state) => url("/oauth/callback/$state"))
,
Tables\Columns\TextColumn::make('priority')->label(__('label.priority')),
Tables\Columns\TextColumn::make('updated_at')->label(__('label.updated_at')),
Tables\Columns\IconColumn::make('enabled')->boolean()->label(__('label.enabled')),
])
->defaultSort('priority', 'desc')
->filters([
//
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\BulkActionGroup::make([
Tables\Actions\DeleteBulkAction::make(),
]),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ManageProviders::route('/'),
];
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Filament\Resources\Oauth\ProviderResource\Pages;
use App\Filament\PageListSingle;
use App\Filament\Resources\Oauth\ProviderResource;
use Filament\Actions;
use Filament\Resources\Pages\ManageRecords;
class ManageProviders extends PageListSingle
{
protected static string $resource = ProviderResource::class;
protected function getHeaderActions(): array
{
return [
Actions\CreateAction::make(),
];
}
}
+54 -31
View File
@@ -3,6 +3,7 @@ namespace App\Http\Controllers;
use App\Http\Resources\UserResource;
use App\Models\OauthClient;
use App\Models\OauthProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
@@ -11,52 +12,74 @@ use Laravel\Passport\Client;
class OauthController extends Controller
{
private int $clientId = 8;
private string $baseUri;
private ?OauthClient $client = null;
// public function __construct()
// {
// $this->baseUri = getSchemeAndHttpHost();
//
// $this->client = OauthClient::query()->find($this->clientId);
// }
public function redirect(Request $request)
/**
* client redirect to authorization server, use oauth_providers config
*
* @param Request $request
* @param string $uuid
* @return \Illuminate\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/
public function redirect(Request $request, string $uuid)
{
// $request->session()->put('state', $state = Str::random(40));
$provider = OauthProvider::query()->where('uuid', $uuid)->firstOrFail();
$request->session()->put('state', $state = Str::random(40));
$query = http_build_query([
'client_id' => $this->client->id,
'redirect_uri' => $this->client->redirect,
'client_id' => $provider->client_id,
'redirect_uri' => $provider->redirect,
'response_type' => 'code',
'scope' => '',
// 'state' => $state,
'state' => $state,
// 'prompt' => 'none', // "none", "consent", or "login"
]);
return redirect($this->baseUri.'/oauth/authorize?'.$query);
$authorizationUrl = sprintf(
'%s%s%s',
$provider->authorization_endpoint_url,
str_contains($provider->authorization_endpoint_url, '?') ? '&' : '?',
$query
);
return redirect($authorizationUrl);
}
public function callback(Request $request)
/**
* authorization server redirect to this url with auth code after user authorized
* and then use auth code to request to authorization server token endpoint url to get access token
*
* @param Request $request
* @param string $uuid
* @return array|mixed
* @throws \Illuminate\Http\Client\ConnectionException
* @throws \Throwable
*/
public function callback(Request $request, string $uuid)
{
// $state = $request->session()->pull('state');
//
// throw_unless(
// strlen($state) > 0 && $state === $request->state,
// \InvalidArgumentException::class
// );
$state = $request->session()->pull('state');
$response = Http::asForm()->post($this->baseUri.'/oauth/token', [
throw_unless(
strlen($state) > 0 && $state === $request->state,
\InvalidArgumentException::class
);
$provider = OauthProvider::query()->where('uuid', $uuid)->firstOrFail();
$response = Http::asForm()->post($provider->token_endpoint_url, [
'grant_type' => 'authorization_code',
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'redirect_uri' => $this->client->redirect,
'client_id' => $provider->client_id,
'client_secret' => $provider->client_secret,
// 'redirect_uri' => url("oauth/login"),
'code' => $request->code,
]);
return $response->json();
$tokenInfo = $response->json();
do_log("tokenInfo: " . $response->body());
//use token get user-info
$response = Http::withToken($tokenInfo['access_token'])->get($provider->user_info_endpoint_url);
$userInfo = $response->json();
do_log("userInfo: " . $response->body());
$userId = data_get($userInfo, $provider->id_claim);
$username = data_get($userInfo, $provider->username_claim);
$email = data_get($userInfo, $provider->email_claim);
dd($userInfo, $userId, $username, $email);
}
public function debug(Request $request)
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace App\Models;
use Laravel\Passport\Client;
use Ramsey\Uuid;
class OauthProvider extends NexusModel
{
protected $fillable = [
'uuid', 'name', 'client_id', 'client_secret', 'authorization_endpoint_url', 'token_endpoint_url',
'user_info_endpoint_url', 'id_claim', 'username_claim', 'email_claim', 'enabled', 'priority',
];
public $timestamps = true;
protected $casts = [
'enabled' => 'boolean',
];
protected static function booted(): void
{
static::creating(function (OauthProvider $model) {
$model->uuid = Uuid\v4();
});
}
}
@@ -11,6 +11,7 @@ use Filament\Pages;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Tables\Columns\Column;
use Filament\Widgets;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
@@ -85,6 +86,10 @@ class AppPanelProvider extends PanelProvider
->paginationPageOptions([10, 25, 50, 100])
;
});
Column::configureUsing(function (Column $section): void {
$section
->disabledClick();
});
}
public function register(): void