Sosyal Giriş Sağlayıcısı Yazma
Giriş, kayıt ve admin ekranlarına "şununla giriş yap" butonu ekleyin. Tek bir sınıf sağlayıcının uçlarını bildirir ve taleplerini bir hesaba eşler.
Genel Bakış
SocialAuth gerçek bir taban sınıfa sahiptir. SocialAuthProvider yetkilendirme adresini, CSRF durumunu, kod takasını ve token doğrulamasını üstlenir. Modülünüz beş uç, bir şema ve bir eşleme metodu bildirir.
Üç sağlayıcı gelir. Keşif kancaya değil kayıt defterine dayanır: Auth::activeProviders() etkin modülleri tutar, yeni bir klasör her ekranda belirir.
Akış: buton, popup, onay, tek geri çağrı, kod takası, doğrulama, hesap çözümü, giriş.
Ön Koşullar
- OAuth 2.0 kod akışı ve OpenID Connect konuşan, RS256 imzalı
id_tokenveren bir sağlayıcı. - Bir client id ve secret, kayıtlı bir yönlendirme adresi.
- Token ve JWKS uçlarına HTTPS erişimi.
- Modül Anatomisi, Modül Yapılandırması.
Yapı
coremio/modules/SocialAuth/Acme/
├── Acme.php class Acme extends \SocialAuthProvider
├── config.php künye + durum + boş ayar anahtarları
├── acme.svg marka logosu, isteğe bağlı (bi-* simgesine geri düşülür)
└── lang/
├── en.php
└── tr.php
feedback() çağırır.
Adım Adım
1. Modül İskeletini Kurun
coremio/modules/SocialAuth/Acme/dizinini açın.config.phpyazın:meta,status => falseve boş birsettingsharitası.lang/en.phpvelang/tr.phpyazın:button-label,field-*çiftleri,error-*, kurulum adımları.- Renkli logoyu
acme.svgolarak bırakın ya dabi-*ikon adı döndürün.
2. Uçlar ve Kimlik Bilgileri
- Tabanı genişletin ve beş uç metodunu uygulayın.
configFields()uygulayın;'type' => 'password'alanı şifrelenir ve maskelenir.testConnection()metodunu sağlayıcıya gerçek bir soru soracak şekilde yazın.- Kurulum adımlarını
setup-step-1,setup-step-2diye kesintisiz yazın.
3. Kimliği Eşleyin
feedback()uygulayın: önceexchange_code(), sonraverify_id_token().- Doğrulanmamış e-postayı hata fırlatarak reddedin; çözücü e-postayla eşler.
- Kimliği hesap başına seçin: Google ve Apple
sub, Microsoftoidkullanır. - Aşağıdaki iki parçalı diziyi döndürün.
4. Etkinleştirin
- Ayarlar'daki Social Auth listesinde sağlayıcınızı bulun.
- Panelin gösterdiği Yönlendirme Adresini sağlayıcı konsoluna kaydedin.
- Kimlik bilgilerini yapıştırın, Bağlantıyı Test Et'e tıklayın, anahtarı açıp kaydedin.
- Giriş sayfasını yenileyin.
Referans
Soyut Sözleşme
Dokuz soyut metot.
// Sunum. ['label' => string, 'icon' => 'bi-*', 'logo' => mutlak url (isteğe bağlı)]
abstract public function provider_meta(): array;
// Ayarlar akordiyonu için kimlik bilgisi şeması. Aşağıdaki anahtar tablosuna bakın.
abstract public function configFields(): array;
// [Bağlantıyı Test Et] butonu. true döndürün, ya da operatörün işine yarayacak bir mesajla fırlatın.
abstract public function testConnection(): bool;
abstract protected function auth_endpoint(): string; // popup'ın kullanıcıyı gönderdiği yer
abstract protected function token_endpoint(): string; // kodun takas edildiği yer
abstract protected function scopes(): string; // örn. 'openid email profile'
abstract protected function jwks_url(): string; // imza doğrulama anahtarları
abstract protected function issuers(): array; // kabul edilen `iss` değerleri
// $ctx = ['code' => string, 'redirect_uri' => string, 'nonce' => string]
abstract public function feedback(array $ctx): array;
feedback()
Bağlam dizisi üç anahtar taşır.
verify_id_token() metoduna geçirin.
return [
// Hesap bağı. `name` bir kullanıcı bilgi anahtarı olur, `value` şifreli kalıcı kimliktir.
'field_info' => [
'name' => "acme_uid",
'value' => Crypt::encode($sub, Config::get("crypt/user")),
],
// Hesabın neyden kurulduğu / neyle eşleştirildiği.
'data' => [
'name' => "Ada", // ad
'surname' => "Lovelace", // soyad
'email' => "[email protected]", // sağlayıcı tarafından doğrulanmış OLMALI
'picture' => "", // avatar url'si, ya da boş dize
'provider_uid' => $sub, // ham kimlik, şifresiz
],
];
Alan Tanımı
Dönen harita alan adı => tanım biçimindedir; ad hem POST adı hem ayar anahtarıdır.
password maskeli ve şifreli, textarea çok satırlı.
password olmayan bir alanı şifreleyip maskeler.
textarea yüksekliği.
Geçersiz Kılma Noktaları
Varsayılanlar düz bir OpenID Connect sağlayıcısına uyar.
| Metot | Varsayılan | Ne zaman geçersiz kılınır |
|---|---|---|
client_id() | saklı client_id | başka bir anahtardaysa; beklenen izleyici de budur. |
client_secret() | çözülmüş client_secret | sabit sır yoksa ve her istekte üretiliyorsa. |
extra_auth_params() | ['prompt' => 'select_account'] | ek parametre gerekiyorsa. Değiştirmeyin, birleştirin. |
accept_issuer($iss, $issuers, $payload) | issuers() ile eşleşme | ihraççı sabit değilse. |
Yetkilendirme adresi, kod takası ve izleyici denetimi client_id() üzerinden geçer. Ayarı doğrudan okumak geçersiz kılmayı etkisiz bırakır.
Taban Yardımcıları
id_token yoksa fırlatır.
$context admin ya da client, $mode login ya da register.
setup-step-N anahtarlarını ilk boşluğa kadar toplar.
Çekirdek Çağrı Noktaları
| Çağrı noktası | Çağırdığı | Neden |
|---|---|---|
Auth::activeProviders() | provider_meta(), enabled(), connection_button() | Kayıt defteri. |
Auth::handleProviderCallback() | enabled(), consume_state(), feedback() | Geri çağrı; mesajınız popup'a döner. |
controllers/admin/settings.php | configFields(), callback_url(), setup_guide() | Ayarlar akordiyonu. |
save_social_provider() | save_settings() | Kayıt; her alan tipine göre filtrelenir. |
test_social_provider() | testConnection() | Test; yazılan değerler önce bellekte uygulanır. |
Örnek
Eksiksiz bir sağlayıcı, sonra çekirdek kodu.
<?php
namespace WISECP\Modules\SocialAuth;
use Config;
use Crypt;
use Exception;
use Filter;
use Utility;
class Acme extends \SocialAuthProvider
{
public function provider_meta(): array
{
return [
'label' => $this->lang["button-label"] ?? "Continue with Acme",
'icon' => 'bi-box-arrow-in-right',
'logo' => $this->url . 'acme.svg',
];
}
public function configFields(): array
{
return [
'client_id' => [
'type' => 'text',
'label' => $this->lang["field-client-id"] ?? "Client ID",
'required' => true,
'placeholder' => "acme-0000-0000",
'description' => $this->lang["field-client-id-desc"] ?? '',
],
'client_secret' => [
'type' => 'password',
'label' => $this->lang["field-client-secret"] ?? "Client Secret",
'required' => true,
'description' => $this->lang["field-client-secret-desc"] ?? '',
],
];
}
protected function auth_endpoint(): string { return "https://id.acme.example/oauth2/authorize"; }
protected function token_endpoint(): string { return "https://id.acme.example/oauth2/token"; }
protected function scopes(): string { return "openid email profile"; }
protected function jwks_url(): string { return "https://id.acme.example/.well-known/jwks.json"; }
protected function issuers(): array { return ["https://id.acme.example"]; }
public function testConnection(): bool
{
$clientId = $this->client_id();
if ($clientId === '')
throw new Exception($this->lang["error-invalid-client-id"] ?? "Please enter a Client ID.");
// Sağlayıcıya bu kimliğin var olup olmadığını sorun: bilinmeyen biri invalid_client,
// gerçek olan redirect_uri_mismatch döndürür. Biçim denetimi ikisini de geçirirdi.
$probe = $this->auth_endpoint() . '?' . http_build_query([
'client_id' => $clientId,
'response_type' => 'code',
'scope' => $this->scopes(),
'redirect_uri' => $this->callback_url(),
'state' => 'wisecp-connectivity-check',
]);
$resp = (string) Utility::HttpRequest($probe, ['timeout' => 8]);
if ($resp === '')
throw new Exception($this->lang["error-unreachable"] ?? "Could not reach Acme.");
if (str_contains($resp, 'invalid_client'))
throw new Exception($this->lang["error-client-not-found"] ?? "Acme does not recognize this Client ID.");
return true;
}
public function feedback(array $ctx): array
{
$code = (string) ($ctx['code'] ?? '');
if ($code === '') throw new Exception("Missing authorization code.");
$token = $this->exchange_code($code, (string) ($ctx['redirect_uri'] ?? ''));
$payload = $this->verify_id_token((string) $token['id_token'], (string) ($ctx['nonce'] ?? ''));
$email = (string) ($payload["email"] ?? '');
if (!$email)
throw new Exception($this->lang["error-no-email"] ?? "Could not read your email address.");
// Şüphede reddet: çözücü mevcut bir hesabı e-postayla eşler, yani doğrulanmamış
// bir adres herkesin başkasının hesabını sahiplenmesine izin verirdi.
if (($payload["email_verified"] ?? false) !== true)
throw new Exception($this->lang["error-email-unverified"] ?? "Acme has not verified this email address.");
$fullName = trim((string) ($payload["given_name"] ?? '') . ' ' . (string) ($payload["family_name"] ?? ''));
$smash = Filter::name_smash(Utility::ucfirst_space(Utility::substr($fullName, 0, 255)));
$sub = (string) ($payload["sub"] ?? '');
if ($sub === '') throw new Exception($this->lang["error-no-account"] ?? "Could not identify your Acme account.");
return [
'field_info' => [
'name' => "acme_uid",
'value' => Crypt::encode($sub, Config::get("crypt/user")),
],
'data' => [
'name' => $smash["first"] ?? '',
'surname' => $smash["last"] ?? '',
'email' => $email,
'picture' => (string) ($payload["picture"] ?? ''),
'provider_uid' => $sub,
],
];
}
}
// classes/Auth.php - handleProviderCallback(), sınıfınızın dokunduğu kısma indirgenmiş.
$st = $provider->consume_state($state); // mode + context + nonce, tek seferlik
if (!$st) return ['status' => 'error', 'message' => "Sign-in could not be completed."];
$result = $provider->feedback([
'code' => $code,
'redirect_uri' => $provider->callback_url(),
'nonce' => (string) ($st['nonce'] ?? ''),
]);
// connectProvider() sonra şunları bu sırayla yapar:
// 1. hesabı field_info ile arar (e-posta değişikliğinden sağ çıkar),
// 2. data.email değerine düşer,
// 3. yalnız mode=register ve üye bağlamında hesabı oluşturur,
// 4. field_info değerini saklar ki sonraki giriş 1. adımla çözülsün.
return Auth::connectProvider('member', 'Acme', $result, (string) ($st['mode'] ?? 'login'));
Oturum açma ekranı kayıt defterine sorar:
// controllers/website/sign.php - giriş sayfası, kayıtta ise aynı çağrı "register" ile.
$this->addData("social_providers", \Auth::activeProviders("login", "client"));
// Tema sonra diziyi gezer; her kayıt ['meta' => [...], 'button' => '<html>'] biçimindedir.
Tuzaklar
Çözücü hesabı e-postayla eşler, yani doğrulanmamış bir adres saldırganın başkası olarak girmesine izin verir. Pozitif doğrulama sinyali arayın.
Hesap için değişmez ve uygulamalar arasında aynı olan bir talep seçin; uygulama başına kimlik, hesabı bir daha üretilmeyecek değere bağlar.
$this->error = '...'; return false; eski kuşaktan kalmadır. Geri çağrı işleyicisi ve Ayarlar operation'ları hatayı yakalayıp mesajını gösterir; dönen false bozuk sonuç sayılır.
Sırlar şifreli yazılır ve eşleşen çözücüyle okunur; elle yazılan değer boş dizeye döner.
Her çağrı noktası Modules::getInstance("SocialAuth", $name) kullanır; bu config ve dili doldurur. Doğrudan kurmak atlar.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.