我为我的api设置了两种身份验证方法:
两者分别像魅力一样。
我尝试将这些系统与此安全配置结合使用:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ALLOWED_TO_SWITCH: ~
ROLE_SUPPORT: ~
ROLE_ADMIN: [ROLE_SONATA_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_SUPPORT, ROLE_ALLOWED_TO_SWITCH]
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
api_key_user:
id: security.user.provider.api_key
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
api:
pattern: ^/api
stateless: true
simple_preauth:
authenticator: security.authentication.authenticator.api_key
fos_oauth: true
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /login
check_path: /login_check
anonymous: ~
logout:
path: /logout
switch_user: true
如果我尝试使用此curl命令获取访问令牌:
curl "http://localhost:8000/oauth/v2/token?client_id=1_2rqa1al0trwgso8g8co4swsks48cwsckgc8cokswkcgos4csog&client_secret=25a78plm6c2ss044k4skckkwoo8kw4kcoccg8sg0skook4sgwg&grant_type=password&username=test&password=test
它有效,我得到一个access_token,但当我尝试使用它时:
curl -X GET http://localhost:8000/api/changelogs.json -H "Authorization: Bearer MmI2OWNkNjhjMGYwOTUyNDA2OTdlMDBjNjA1YmI3MjVhNTBiMTNhMjI0MGE1YmM3NzgwNjVmZWZmYWNhM2E4YQ" | json_pp
我明白了:
{
"error" : "invalid_grant",
"error_description" : "The provided access token is invalid."
}
通过停用我的single_preauth api密钥验证器,它可以工作,我可以访问我的API。
似乎我的api密钥验证器阻止了所有其他系统。
在这里,我的ApiKeyAuthenticator类:
class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
{
private $userProvider;
/**
* @param ApiKeyUserProvider $userProvider
*/
public function __construct(ApiKeyUserProvider $userProvider)
{
$this->userProvider = $userProvider;
}
/**
* {@inheritdoc}
*/
public function createToken(Request $request, $providerKey)
{
$apiKey = str_replace('Bearer ', '', $request->headers->get('Authorization', ''));
if (!$apiKey) {
throw new BadCredentialsException('No API key given.');
}
return new PreAuthenticatedToken('anon.', $apiKey, $providerKey);
}
/**
* {@inheritdoc}
*/
public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
$apiKey = $token->getCredentials();
$username = $this->userProvider->getUsernameForApiKey($apiKey);
if (!$username) {
throw new AuthenticationException('The provided access token is invalid.');
}
$user = $this->userProvider->loadUserByUsername($username);
return new PreAuthenticatedToken(
$user,
$apiKey,
$providerKey,
$user->getRoles()
);
}
/**
* {@inheritdoc}
*/
public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
}
/**
* {@inheritdoc}
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
return new JsonResponse([
'error' => 'invalid_grant',
'error_description' => $exception->getMessage()
], 401);
}
}
但我找不到原因。
如何组合这两种验证方法?
感谢您的帮助。
答案 0 :(得分:0)
最终找到了如何处理它但不确定它是更好和正确的方法。
不要犹豫,建议改进评论! ;)
首先,从fos_oauth
文件中删除security.yml
密钥。它应该看起来像:
security:
firewalls:
# [...]
api:
pattern: ^/api
stateless: true
# This will handle both oauth access token and simple private token
simple_preauth:
authenticator: security.authentication.authenticator.api_key
# [...]
在ApiKeyUserProvider::getUsernameForApiKey
方法上,您将搜索自定义API密钥管理器和OAuth访问令牌管理器。
完整的课程应该如下所示。
class ApiKeyUserProvider implements UserProviderInterface
{
/**
* @var UserManagerInterface
*/
private $userManager;
/**
* @var ApiKeyManager
*/
private $apiKeyManager;
/**
* @var AccessTokenManagerInterface
*/
private $accessTokenManager;
/**
* @param UserManagerInterface $userManager
* @param ApiKeyManager $apiKeyManager
* @param AccessTokenManagerInterface $accessTokenManager
*/
public function __construct(UserManagerInterface $userManager, ApiKeyManager $apiKeyManager, AccessTokenManagerInterface $accessTokenManager)
{
$this->userManager = $userManager;
$this->apiKeyManager = $apiKeyManager;
$this->accessTokenManager = $accessTokenManager;
}
/**
* @param string $apiKey
*
* @return string|null
*/
public function getUsernameForApiKey($apiKey)
{
// FOSOAuth system
$token = $this->accessTokenManager->findTokenByToken($apiKey);
if ($token) {
return $token->getUser()->getUsername();
}
// Private key system
return $this->apiKeyManager->getUsernameForToken($apiKey);
}
/**
* {@inheritdoc}
*/
public function loadUserByUsername($username)
{
return $this->userManager->findUserByUsername($username);
}
/**
* {@inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
throw new UnsupportedUserException();
}
/**
* {@inheritdoc}
*/
public function supportsClass($class)
{
return 'FOS\UserBundle\Model\User' === $class;
}
}
瞧!私有和OAuth令牌都得到了正确管理。