Dla przypomnienia, używam PHP 7.0.0, w Vagrant Box z PHPStorm. Och, i Symfony 3.Symfony - Autoryzacja z API Reklamowe - tokenu żądania użytkownik jest null
Podążam za dokumentacją API Key Authentication. Moim celem jest:
- Aby umożliwić użytkownikowi dostarczenie klucza jako parametr GET
apiKey
uwierzytelnienia dla dowolny trasie, z wyjątkiem deweloper profiler itp oczywiście - Aby umożliwić deweloper napisać
$request->getUser()
w kontrolerze aby uzyskać aktualnie zalogowanego użytkownika
Moim problemem jest to, że chociaż wierzę, że już po dokumentacji pismo, ja wciąż dostaję null
dla $request->getUser()
w kontrolerze.
Uwaga: Usunąłem sprawdzanie błędów, aby zachować kod krótki
ApiKeyAuthenticator.php
Rzecz, która przetwarza część wniosku o chwycić klucz API z niego . Może to być nagłówek lub cokolwiek innego, ale trzymam się
apiKey
z GET.
Różnice w dokumentacji, prawie 0 oprócz tego staram się utrzymać użytkownika uwierzytelnionego w sesji po this part dokumentów.
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface
{
public function createToken(Request $request, $providerKey)
{
$apiKey = $request->query->get('apiKey');
return new PreAuthenticatedToken(
'anon.',
$apiKey,
$providerKey
);
}
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
$apiKey = $token->getCredentials();
$username = $userProvider->getUsernameForApiKey($apiKey);
// The part where we try and keep the user in the session!
$user = $token->getUser();
if ($user instanceof ApiKeyUser) {
return new PreAuthenticatedToken(
$user,
$apiKey,
$providerKey,
$user->getRoles()
);
}
$user = $userProvider->loadUserByUsername($username);
return new PreAuthenticatedToken(
$user,
$apiKey,
$providerKey,
$user->getRoles()
);
}
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
}
}
ApiKeyUserProvider.php
Zwyczaj dostawcą użytkownik załadować obiekt użytkownika z dowolnego miejsca mogą być ładowane z - mam trzymać z domyślnym realizacji DB.
Różnice: tylko fakt, że muszę wstrzykiwać repozytorium do konstruktora do wykonywania połączeń do DB, jak docs wspomina się, ale nie pokazują, a także powrót $user
w refreshUser()
.
class ApiKeyUserProvider implements UserProviderInterface
{
protected $repo;
// I'm injecting the Repo here (docs don't help with this)
public function __construct(UserRepository $repo)
{
$this->repo = $repo;
}
public function getUsernameForApiKey($apiKey)
{
$data = $this->repo->findUsernameByApiKey($apiKey);
$username = (!is_null($data)) ? $data->getUsername() : null;
return $username;
}
public function loadUserByUsername($username)
{
return $this->repo->findOneBy(['username' => $username]);
}
public function refreshUser(UserInterface $user)
{
// docs state to return here if we don't want stateless
return $user;
}
public function supportsClass($class)
{
return 'Symfony\Component\Security\Core\User\User' === $class;
}
}
ApiKeyUser.php
To jest mój obiekt niestandardowy użytkownika.
Jedyną różnicą, którą mam tutaj jest to, że zawiera adnotacje doktryny (usunięte dla twojego zdrowia psychicznego) i niestandardowe pole dla tokena. Usunęłam też \Serializable
, ponieważ nic nie robiłam i najwyraźniej Symfony potrzebuje tylko wartości $id
, aby odtworzyć użytkownika, który sam może zrobić.
class ApiKeyUser implements UserInterface
{
private $id;
private $username;
private $password;
private $email;
private $salt;
private $apiKey;
private $isActive;
public function __construct($username, $password, $salt, $apiKey, $isActive = true)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->apiKey = $apiKey;
$this->isActive = $isActive;
}
//-- SNIP getters --//
}
security.yml
# Here is my custom user provider class from above
providers:
api_key_user_provider:
id: api_key_user_provider
firewalls:
# Authentication disabled for dev (default settings)
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# My new settings, with stateless set to false
secured_area:
pattern: ^/
stateless: false
simple_preauth:
authenticator: apikey_authenticator
provider:
api_key_user_provider
services.yml
Oczywiście muszę być w stanie wstrzyknąć repozytorium do dostawcy.
api_key_user_repository:
class: Doctrine\ORM\EntityRepository
factory: ["@doctrine.orm.entity_manager", getRepository]
arguments: [AppBundle\Security\ApiKeyUser]
api_key_user_provider:
class: AppBundle\Security\ApiKeyUserProvider
factory_service: doctrine.orm.default_entity_manager
factory_method: getRepository
arguments: ["@api_key_user_repository"]
apikey_authenticator:
class: AppBundle\Security\ApiKeyAuthenticator
public: false
debugowanie. Warto zauważyć, że w ApiKeyAuthenticator.php
wywołanie $user = $token->getUser();
w authenticateToken()
zawsze pokazuje użytkownika anon.
, więc wyraźnie nie jest on przechowywany w sesji.
również pamiętać, jak na dnie uwierzytelnienia mamy rzeczywiście powrócić nową PreAuthenticatedToken
z użytkownikiem znaleziony w bazie danych:
Więc to wyraźnie stwierdzono mnie i zwraca to, co ma tutaj, ale wywołanie użytkownika w kontrolerze zwraca null
. Co ja robię źle? Czy to nie serializowanie w sesji z powodu mojego niestandardowego użytkownika lub czegoś podobnego? Próbowałem ustawić wszystkie właściwości użytkownika jako publiczne w jakimś miejscu w sugerowanej dokumentacji, ale to nie miało znaczenia.
można spróbować to sprawdzić, należy dodać do zapory: 'access_control: - {ścieżkę:^/, role: IS_AUTHENTICATED_ANONYMOUSLY}' – COil
Dodałem to jako klucz pod 'security' w' security.yml '. Bez zmiany. – Jimbo
Czy możesz spróbować, ustawiając wszystkie swoje właściwości w klasie ApiKeyUser jako chronione? – hasumedic