Laravel Test 7 ve Laravel Passport 9.3'ü Kişisel Erişim İstemcisi ile kullanmak, "Nesne olmayanın özellik 'kimliğini' almaya çalışma" istisnasını verir
Durum bilgisi olmayan bir API ile birlikte özel bir kimlik doğrulama şeması (genel anahtarlara dayalı) tasarlıyorum ve Passport'un kimlik doğrulama sonrası talepleri karşılayacağına karar verdim.
Kimlik doğrulamanın başarılı olduğunu ve kullanıcının kimliğinin doğrulandığını varsayarsak, bir Kişisel Erişim Jetonu alacaklar ve jetonu diğer tüm talepler için kullanacaklardır. Yaşadığım sorun (yine de çeşitli forumlarda ve Stack Overflow'da çok fazla arama yaptıktan sonra), Laravel'in yerleşik test paketini createToken () yönteminde kullanırken, bir (kuşkusuz yaygın) bir istisna oluşturmasıdır:
"ErrorException: Nesne olmayanın 'id' özelliğini almaya çalışılıyor".
Tinker aracılığıyla manuel olarak bir kullanıcı oluşturabiliyorum ve Tinker aracılığıyla bir token oluşturabiliyorum. Ancak kimlik doğrulamasından sonra bu işlemi otomatikleştirmeye çalışırken sorun yaşıyorum .
İlgili kod pasajı kimlik doğrulama sonrası:
Auth::login($user); $user = Auth::user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->expires_at = Carbon::now()->addWeeks(1); $token->save();
return response()->json([
"access_token" => $tokenResult->accessToken, "token_type" => "Bearer", "expires_at" => Carbon::parse( $tokenResult->token->expires_at)->toDateTimeString()
],
200);
Kullanıcının oturum açtığından emin olmak için kullanıcıda Auth :: login'yi manuel olarak çağırdım ve Auth :: user () kullanıcıyı döndürür (boş değil). Üçüncü kod satırı çalıştırıldığında, aşağıdaki mini yığın izleme ile istisna atılır (istenirse tam bir yığın izleme sağlayabilirim).
laravel\passport\src\PersonalAccessTokenFactory.php:100
laravel\passport\src\PersonalAccessTokenFactory.php:71
laravel\passport\src\HasApiTokens.php:67
app\Http\Controllers\Auth\LoginController.php:97
laravel\framework\src\Illuminate\Routing\Controller.php:54
laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php:45
Bunu hata ayıklama yoluyla birkaç kez çalıştırarak - sınıf çağrılıp yüklense ve İstemci ControllerDispatcher -> Client :: find (id) aracılığıyla bulunur ve PersonalAccessTokenFactory'ye ulaştığında ClientRepository'de bulunur. $client passed in is null (which explains why the $client-> id bulunamıyor, ancak bu noktada $ client'ın neden boş olduğuna dair hiçbir fikrim yok).
protected function createRequest($client, $userId, array $scopes)
{
$secret = Passport::$hashesClientSecrets ? Passport::$personalAccessClientSecret : $client->secret;
return (new ServerRequest)->withParsedBody([
'grant_type' => 'personal_access',
'client_id' => $client->id,
...
}
Belgelerden ve diğer gönderilerden biraz rehberlik ederek yaptığım / denediğim şeyler:
- Tinker'da manuel olarak bir kullanıcı oluşturdu ve jetonu Tinker aracılığıyla oluşturdu - bu işe yarıyor .
- Belirteç oluşturmaya çalışmadan önce kullanıcının oturum açtığından emin olun.
- passport: install (ve --force seçeneğini ekleyerek)
- Sağlanan Kişisel Erişim İstemci pasaportla oluşturulur: müşteri - kişisel
- AuthServiceProvider :: boot () 'nin ClientID ve Client Secret (.env içinde) içerdiğinden emin olun.
- migrate: yenileme ve ardından pasaport: install --force
- Passport'un tamamen kaldırılması, tüm dosyaların, anahtarların, geçişlerin ve DB girişlerinin kaldırılması, ardından bir geçiş: Passport'un yenilenmesi ve yeniden yüklenmesi, ayrıca ek bir kişisel erişim istemcisi (pasaport sırasında oluşturulsa bile: yükleme).
Bu noktada başka nereye bakacağım / başka ne deneyeceğim konusunda emin değilim, bu nedenle herhangi bir yardım veya rehberlik çok takdir edilecektir!
Yanıtlar
Sonunda çözümü keşfettim. Sorun çok katmanlı olup, kısmen test ve Passport Kişisel Erişim İstemcileri ile ilgili olarak güncel olmayan Laravel belgeleriyle ilgilidir.
Problemin ilk kısmı, birim testimde RefreshDatabase özelliği kullanmakla ilgiliydi. Bu, boş veri kümelerine sahip sahte bir veritabanı oluşturduğundan, istemcilerin kendileri gerçek veritabanında ve .env dosyasında bulunsa da, test çalıştırıldığında, test bu istemcileri sahte veritabanında var olarak görmez. Bu sorunu çözmek için , test çalıştırılmadan önce kurulum işlevinde bir istemci oluşturmanız gerekir .
public function setUp() : void
{
parent::setUp();
$this->createClient(); //Private method->Full code below
}
Bu, test sırasında boş bir istemciye sahip olma sorununu çözer, ancak Laravel 7'den başlayarak, Kişisel Erişim İstemcileri için kimliğin ve istemci sırrının .env dosyası içinde tutulması gerektiğine dair bir gereksinim ekledi . Testi çalıştırırken, test .env dosyasında gerçek istemci kimliğini ve sırrını görecek ve sahte veritabanında oluşturulan ve depolanan istemciyle bunları doğrulayamayacak ve başka bir istisna döndü: "İstemci Kimlik Doğrulaması Başarısız".
Bu sorunun çözümü, ana proje dizininizde bir .env.testing dosyası oluşturmak, .env dosya içeriğinizi buna kopyalamak ve aşağıdaki anahtarların ana oluşturulan Kişisel Erişim İstemciniz için değerlerle var olmasını sağlamak veya sırrı kopyalamaktır. sadece test için oluşturulmuş bir müşteriden (ikincisini tavsiye ederim).
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=1
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=unhashed-client-secret-value
Ardından aşağıdaki kodu kullanarak $ clientSecret değerinin .env.testing dosyanızdaki anahtar değeriyle aynı olduğundan emin olun.
private function createClient() : void
{
$clientRepository = new ClientRepository(); $client = $clientRepository->createPersonalAccessClient( null, 'Test Personal Access Client', 'http://localhost' ); DB::table('oauth_personal_access_clients')->insert([ 'client_id' => $client->id,
'created_at' => new DateTime,
'updated_at' => new DateTime,
]);
$clientSecret = 'unhashed-client-secret-value'; $client->setSecretAttribute($clientSecret); $client->save();
}
Bu, yeni bir istemci yaratacak, gizli özniteliğini değişkendeki değere ayarlayacak ve sahte veritabanı sırrını aynı değeri içerecek şekilde güncelleyecektir. Umarım bu, aynı sorunu yaşayan herkese yardımcı olur.