feat: add app and database modules
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use App\Services\SystemConfig\SystemConfigService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Socialite\Facades\Socialite;
|
||||
|
||||
class SocialAuthController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected SystemConfigService $systemConfig
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Redirect to Provider OAuth
|
||||
*/
|
||||
public function redirect(string $provider)
|
||||
{
|
||||
$this->ensureFeatureEnabled($provider);
|
||||
|
||||
// Save provider to session for the unified callback
|
||||
session(['social_auth_provider' => $provider]);
|
||||
|
||||
return Socialite::driver($provider)->redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Provider Callback
|
||||
*/
|
||||
public function callback()
|
||||
{
|
||||
$provider = session('social_auth_provider');
|
||||
|
||||
if (! $provider) {
|
||||
return redirect('/login')->with('error', __('Authentication provider not found in session.'));
|
||||
}
|
||||
|
||||
$this->ensureFeatureEnabled($provider);
|
||||
|
||||
try {
|
||||
$socialUser = Socialite::driver($provider)->user();
|
||||
} catch (Exception $e) {
|
||||
return redirect('/login')->with('error', __(':provider authentication failed.', ['provider' => ucfirst($provider)]));
|
||||
}
|
||||
|
||||
$idColumn = $provider.'_id'; // google_id, facebook_id, github_id
|
||||
|
||||
// Reject if the OAuth provider signals the email is not verified
|
||||
$emailVerified = $socialUser->user['email_verified'] ?? null;
|
||||
if ($emailVerified === false) {
|
||||
return redirect('/login')->with('error', __('Your :provider email address is not verified. Please verify it and try again.', ['provider' => ucfirst($provider)]));
|
||||
}
|
||||
|
||||
// Primary lookup: by provider-specific ID (not spoofable)
|
||||
$user = User::where($idColumn, $socialUser->id)->first();
|
||||
|
||||
// Secondary lookup: by email only if no provider-ID match exists yet
|
||||
// (covers first-time OAuth login for users who registered via email)
|
||||
if (! $user && $socialUser->email) {
|
||||
$byEmail = User::where('email', $socialUser->email)->first();
|
||||
if ($byEmail) {
|
||||
// Only link if the existing account does NOT already belong to a different OAuth identity
|
||||
if (empty($byEmail->{$idColumn})) {
|
||||
$user = $byEmail;
|
||||
} else {
|
||||
// Email already linked to a different identity on this provider — refuse silently
|
||||
// to avoid leaking that the account exists or letting an attacker take it over.
|
||||
return redirect('/login')->with('error', __('This email is already linked to a different account. Please sign in with your original method.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! $user) {
|
||||
// Register new user
|
||||
$user = User::create([
|
||||
'name' => $socialUser->name ?? $socialUser->nickname ?? $socialUser->email,
|
||||
'email' => $socialUser->email,
|
||||
$idColumn => $socialUser->id,
|
||||
'avatar' => $socialUser->avatar,
|
||||
'password' => bcrypt(Str::random(32)),
|
||||
]);
|
||||
|
||||
// Assign default role
|
||||
$user->assignRole('User');
|
||||
} else {
|
||||
// Sync Social ID and Avatar
|
||||
$user->update([
|
||||
$idColumn => $socialUser->id,
|
||||
'avatar' => $socialUser->avatar,
|
||||
]);
|
||||
}
|
||||
|
||||
Auth::login($user, true);
|
||||
|
||||
session()->forget('social_auth_provider');
|
||||
session()->regenerate();
|
||||
|
||||
return redirect()->intended('/dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the requested provider is enabled in settings
|
||||
*/
|
||||
protected function ensureFeatureEnabled(string $provider): void
|
||||
{
|
||||
$settingKey = 'feature_'.$provider.'_oauth';
|
||||
|
||||
if ($provider === 'facebook' || $provider === 'github') {
|
||||
// GitHub and Facebook keys follow the 'feature_{provider}_oauth' pattern
|
||||
}
|
||||
|
||||
abort_unless($this->systemConfig->get($settingKey, false), 404, __('Provider not enabled.'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user