Để lưu nội dung, tôi đang sử dụng PHP 7.0.0, trong hộp Vagrant, với PHPStorm. Oh, và Symfony 3.Symfony - Xác thực bằng Mã thông báo API - Người dùng mã thông báo yêu cầu là null
Tôi đang theo dõi tài liệu API Key Authentication. Mục tiêu của tôi là:
- Để cho phép người sử dụng để cung cấp một chìa khóa như một tham số GET
apiKey
để xác thực cho bất kỳ tuyến đường, ngoại trừ vv phát triển hồ sơ rõ ràng - Để cho phép các nhà phát triển để viết
$request->getUser()
trong một bộ điều khiển để người dùng hiện đã đăng nhập
Vấn đề của tôi là mặc dù tôi tin rằng tôi vẫn đang theo dõi tài liệu, tôi vẫn nhận được null
cho $request->getUser()
trong bộ điều khiển.
Lưu ý: Tôi đã gỡ bỏ kiểm tra lỗi để giữ mã ngắn
ApiKeyAuthenticator.php
Điều mà xử lý phần của yêu cầu để lấy chìa khóa API từ nó . Nó có thể là một tiêu đề hoặc bất cứ điều gì, nhưng tôi đang gắn bó với
apiKey
từ GET.
Sự khác biệt về tài liệu, ngoài ra tôi còn cố gắng giữ cho người dùng được xác thực trong phiên sau this part tài liệu.
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 nhà cung cấp sử dụng
Tục để tải một đối tượng người dùng từ bất cứ nơi nào nó có thể được nạp từ - Tôi gắn bó với việc thực hiện DB mặc định.
Sự khác biệt: chỉ có thực tế là tôi phải tiêm kho vào các nhà xây dựng để thực hiện cuộc gọi đến DB, như các tài liệu ám chỉ đến nhưng không hiển thị, và cũng có thể trở $user
trong 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
Đây là đối tượng của tôi người dùng tùy chỉnh.
Sự khác biệt duy nhất tôi có ở đây là nó chứa chú thích học thuyết (loại bỏ cho sự tỉnh táo của bạn) và trường tùy chỉnh cho mã thông báo. Ngoài ra, tôi đã xóa \Serializable
vì nó dường như không hoạt động và Symfony chỉ cần giá trị $id
để tạo lại người dùng mà chính nó có thể tự thực hiện.
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
Rõ ràng tôi cần để có thể tiêm kho thành nhà cung cấp.
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
Gỡ lỗi. Thật thú vị khi lưu ý rằng, trong ApiKeyAuthenticator.php
, cuộc gọi tới $user = $token->getUser();
trong authenticateToken()
luôn hiển thị người dùng anon.
, do đó, rõ ràng là không được lưu trữ trong phiên.
Cũng lưu ý như thế nào ở dưới cùng của xác thực chúng tôi thực sự trở lại mới PreAuthenticatedToken
với một người dùng tìm thấy từ cơ sở dữ liệu:
Vì vậy, nó được tìm thấy rõ ràng tôi và trả lại những gì nó được cho là ở đây, nhưng cuộc gọi của người dùng trong bộ điều khiển trả về null
. Tôi đang làm gì sai? Nó là một thất bại trong việc nối tiếp vào phiên vì người dùng tùy chỉnh của tôi hay gì đó? Tôi đã thử đặt tất cả các thuộc tính người dùng thành công khai ở đâu đó trong tài liệu được đề xuất nhưng điều đó không có sự khác biệt.
Bạn có thể thử để kiểm tra điều này, thêm vào tường lửa của bạn: 'access_control: - {path:^/, vai trò: IS_AUTHENTICATED_ANONYMOUSLY}' – COil
tôi thêm này như một chìa khóa dưới 'security' trong' security.yml '. Không thay đổi. – Jimbo
Bạn có thể thử bằng cách đặt tất cả các thuộc tính của bạn trong lớp ApiKeyUser như được bảo vệ không? – hasumedic