mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-14 12:30:49 +08:00
finish oauth provider + docker service wait for MySQL
This commit is contained in:
@@ -45,20 +45,23 @@ class Handler extends ExceptionHandler
|
||||
if (app()->runningInConsole()) {
|
||||
return;
|
||||
}
|
||||
$this->reportable(function (InsufficientPermissionException $e) {
|
||||
if (request()->expectsJson()) {
|
||||
return response()->json(fail($e->getMessage(), request()->all()), 403);
|
||||
$request = request();
|
||||
$this->reportable(function (InsufficientPermissionException $e) use ($request) {
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(fail($e->getMessage(), $request->all()), 403);
|
||||
} else {
|
||||
return abort(403);
|
||||
}
|
||||
});
|
||||
$this->renderable(function (PassportAuthenticationException $e) {
|
||||
$request = request();
|
||||
$this->renderable(function (PassportAuthenticationException $e) use ($request) {
|
||||
return response()->redirectTo(sprintf("%s/login.php?returnto=%s", $request->getSchemeAndHttpHost(), urlencode($request->fullUrl())));
|
||||
});
|
||||
|
||||
//Other Only handle in json request
|
||||
if (!request()->expectsJson()) {
|
||||
if (!$request->expectsJson()) {
|
||||
$this->renderable(function (NexusException $e) use ($request) {
|
||||
return redirect(url('/error?error=' . urlencode($e->getMessage())));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Filament\Resources\Oauth;
|
||||
use App\Filament\Resources\Oauth\ProviderResource\Pages;
|
||||
use App\Filament\Resources\Oauth\ProviderResource\RelationManagers;
|
||||
use App\Models\OauthProvider;
|
||||
use App\Models\User;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
@@ -71,6 +72,14 @@ class ProviderResource extends Resource
|
||||
Forms\Components\TextInput::make('email_claim')
|
||||
->label(__('oauth.email_claim'))
|
||||
,
|
||||
Forms\Components\TextInput::make('level_claim')
|
||||
->label(__('oauth.level_claim'))
|
||||
,
|
||||
Forms\Components\TextInput::make('level_limit')
|
||||
->numeric()
|
||||
->label(__('oauth.level_limit'))
|
||||
->helperText(__('oauth.level_limit_help'))
|
||||
,
|
||||
Forms\Components\TextInput::make('priority')
|
||||
->label(__('label.priority'))
|
||||
->default(0)
|
||||
@@ -88,6 +97,7 @@ class ProviderResource extends Resource
|
||||
return $table
|
||||
->columns([
|
||||
Tables\Columns\TextColumn::make('id'),
|
||||
Tables\Columns\TextColumn::make('name')->label(__('label.name')),
|
||||
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')),
|
||||
@@ -97,6 +107,7 @@ class ProviderResource extends Resource
|
||||
,
|
||||
Tables\Columns\TextColumn::make('priority')->label(__('label.priority')),
|
||||
Tables\Columns\TextColumn::make('updated_at')->label(__('label.updated_at')),
|
||||
Tables\Columns\TextColumn::make('level_limit')->label(__('oauth.level_limit')),
|
||||
Tables\Columns\IconColumn::make('enabled')->boolean()->label(__('label.enabled')),
|
||||
])
|
||||
->defaultSort('priority', 'desc')
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Exceptions\NexusException;
|
||||
use App\Http\Resources\UserResource;
|
||||
use App\Models\OauthClient;
|
||||
use App\Models\OauthProvider;
|
||||
use App\Models\SocialAccount;
|
||||
use App\Models\User;
|
||||
use App\Repositories\UserRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -26,7 +30,7 @@ class OauthController extends Controller
|
||||
|
||||
$query = http_build_query([
|
||||
'client_id' => $provider->client_id,
|
||||
'redirect_uri' => $provider->redirect,
|
||||
'redirect_uri' => $this->getRedirectUri($provider),
|
||||
'response_type' => 'code',
|
||||
'scope' => '',
|
||||
'state' => $state,
|
||||
@@ -42,6 +46,11 @@ class OauthController extends Controller
|
||||
|
||||
}
|
||||
|
||||
private function getRedirectUri(OauthProvider $provider): string
|
||||
{
|
||||
return sprintf("%s/oauth/callback/%s", getSchemeAndHttpHost(), $provider->uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -63,23 +72,98 @@ class OauthController extends Controller
|
||||
|
||||
$provider = OauthProvider::query()->where('uuid', $uuid)->firstOrFail();
|
||||
|
||||
$response = Http::asForm()->post($provider->token_endpoint_url, [
|
||||
$params = [
|
||||
'grant_type' => 'authorization_code',
|
||||
'client_id' => $provider->client_id,
|
||||
'client_secret' => $provider->client_secret,
|
||||
// 'redirect_uri' => url("oauth/login"),
|
||||
'redirect_uri' => $this->getRedirectUri($provider),
|
||||
'code' => $request->code,
|
||||
]);
|
||||
];
|
||||
$response = Http::asForm()->post($provider->token_endpoint_url, $params);
|
||||
$tokenInfo = $response->json();
|
||||
do_log("tokenInfo: " . $response->body());
|
||||
if (empty($tokenInfo['access_token'])) {
|
||||
do_log("Get tokenInfo with: " . json_encode($params) . " error: " . $response->body(), 'error');
|
||||
throw new NexusException(nexus_trans('oauth.get_access_token_error', ['error' => $tokenInfo['error'] ?? '']));
|
||||
}
|
||||
//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);
|
||||
$providerUserId = data_get($userInfo, $provider->id_claim);
|
||||
if (empty($providerUserId)) {
|
||||
throw new NexusException(nexus_trans('oauth.get_provider_user_id_error', ['id_claim' => $provider->id_claim]));
|
||||
}
|
||||
$providerUsername = data_get($userInfo, $provider->username_claim);
|
||||
$providerEmail = data_get($userInfo, $provider->email_claim);
|
||||
$providerLevel = data_get($userInfo, $provider->level_claim);
|
||||
$homeUrl = getSchemeAndHttpHost() . "/index.php";
|
||||
$socialAccount = SocialAccount::query()
|
||||
->where('provider_id', $provider->id)
|
||||
->where('provider_user_id', $providerUserId)
|
||||
->first();
|
||||
if ($socialAccount) {
|
||||
//already bind, login directly
|
||||
$authUser = $socialAccount->user;
|
||||
logincookie($authUser->id, $authUser->auth_key);
|
||||
return redirect($homeUrl);
|
||||
}
|
||||
$minLevel = $provider->level_limit;
|
||||
if ($minLevel) {
|
||||
if (!$providerLevel) {
|
||||
throw new NexusException(nexus_trans('oauth.get_provider_level_error', ['level_claim' => $provider->level_claim]));
|
||||
}
|
||||
if ($providerLevel < $minLevel) {
|
||||
throw new NexusException(nexus_trans("oauth.provider_level_not_allowed", ['level_limit' => $provider->level_limit]));
|
||||
}
|
||||
}
|
||||
if ($providerEmail) {
|
||||
$sameEmailUser = User::query()->where('email', $providerEmail)->first();
|
||||
if ($sameEmailUser) {
|
||||
//login to bind is better, not implement this time
|
||||
throw new NexusException(nexus_trans('oauth.provider_email_already_exists', ['email' => $providerEmail]));
|
||||
}
|
||||
}
|
||||
$newUser = $this->createUser($providerUsername, $providerEmail);
|
||||
$socialAccountData = [
|
||||
'user_id' => $newUser->id,
|
||||
'provider_id' => $provider->id,
|
||||
'provider_user_id' => $providerUserId,
|
||||
'provider_username' => $providerUsername,
|
||||
'provider_email' => $providerEmail,
|
||||
];
|
||||
SocialAccount::query()->create($socialAccountData);
|
||||
do_log(sprintf("newUser: %s, socialAccount: %s", json_encode($newUser), json_encode($socialAccountData)));
|
||||
logincookie($newUser->id, $newUser->auth_key);
|
||||
return redirect($homeUrl);
|
||||
}
|
||||
|
||||
private function createUser($username, $email): User
|
||||
{
|
||||
if ($username) {
|
||||
if (User::query()->where('username', $username)->exists()) {
|
||||
//already in use
|
||||
$username .= Str::random(2);
|
||||
}
|
||||
} else {
|
||||
$username = $email;
|
||||
}
|
||||
$password = Str::random(10);
|
||||
$userData = [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
'password_confirmation' => $password,
|
||||
];
|
||||
$userRep = new UserRepository();
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$userData['username'] = $username;
|
||||
try {
|
||||
return $userRep->store($userData);
|
||||
} catch (\Throwable $e) {
|
||||
do_log($e->getMessage(), "error");
|
||||
}
|
||||
$username = Str::random(2) . $username;
|
||||
}
|
||||
throw new NexusException("Unable to create user");
|
||||
}
|
||||
|
||||
public function debug(Request $request)
|
||||
|
||||
@@ -37,4 +37,9 @@ class ToolController extends Controller
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
public function error(Request $request)
|
||||
{
|
||||
return view('error', ['error' => $request->query('error')]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Locale
|
||||
/** @var Response $response */
|
||||
$response = $next($request);
|
||||
if ($response instanceof Response || $response instanceof JsonResponse) {
|
||||
$response->header('X-Request-Id', nexus()->getRequestId())->header('X-NexusPHP-Version', VERSION_NUMBER);
|
||||
$response->header('X-Request-Id', nexus()->getRequestId())->header('X-Nexusphp-Version', VERSION_NUMBER);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ class UserResource extends JsonResource
|
||||
'added_human' => gettime($this->added),
|
||||
'last_access' => format_datetime($this->last_access),
|
||||
'last_access_human' => gettime($this->last_access),
|
||||
'last_login' => format_datetime($this->last_login),
|
||||
'last_login_human' => gettime($this->last_login),
|
||||
'class' => $this->class,
|
||||
'class_text' => $this->class_text,
|
||||
'avatar' => $this->avatar,
|
||||
@@ -44,6 +46,7 @@ class UserResource extends JsonResource
|
||||
'seedtime_text' => mkprettytime($this->seedtime),
|
||||
'leechtime' => $this->leechtime,
|
||||
'leechtime_text' => mkprettytime($this->leechtime),
|
||||
'share_ratio' => get_ratio($this->id),
|
||||
'inviter' => new UserResource($this->whenLoaded('inviter')),
|
||||
'valid_medals' => MedalResource::collection($this->whenLoaded('valid_medals')),
|
||||
];
|
||||
|
||||
@@ -10,6 +10,7 @@ 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',
|
||||
'level_claim', 'level_limit',
|
||||
];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
22
app/Models/SocialAccount.php
Normal file
22
app/Models/SocialAccount.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Laravel\Passport\Client;
|
||||
use Ramsey\Uuid;
|
||||
use function Ramsey\Uuid;
|
||||
|
||||
class SocialAccount extends NexusModel
|
||||
{
|
||||
protected $fillable = [
|
||||
'user_id', 'provider_id', 'provider_user_id', 'provider_username', 'provider_email',
|
||||
];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user