我想使用OAuth2和Symfony2(实际上是Symfony3)对我的API进行服务器到服务器身份验证。我正在使用FOSOAuthServerBundle
。
远程服务器不会代表任何用户发出请求,因此我认为client_credentials
是正确的授权类型。
我创建了一个客户端,并且能够获取访问令牌。但是,我遇到了使用client_credentials
令牌保护端点的问题。这就是我的security.yml
firewalls:
api:
pattern: ^/api/v1
fos_oauth: true
stateless: true
anonymous: false # can be omitted as its default value
access_control:
- { path: ^/api/v1, roles: [ IS_AUTHENTICATED_FULLY ] }
当我尝试使用Bearer Authorization标头访问/api/v1
中的内容时,出现错误
Full authentication is required to access this resource
以下是示例请求:
GET /app_dev.php/api/v1/user HTTP/1.1
Host: local.dev
Authorization: Bearer NDFhMzViZjQ2YjMyYjFlNzBjZTZiMTU2ZjdhY2I4ZmZhZjY2MmVkMjU3NzNjNDE2NGI2YzEzMWFjZGQ5MzE4NA
我认为问题是因为我使用的是client_credentials,所以没有用户,因此IS_FULLY_AUTHENTICATED不是真的。如果是这种情况,如何在没有用户的情况下对客户端进行身份验证?
注意:我也尝试删除
行access_control:
- { path: ^/api/v1, roles: [ IS_AUTHENTICATED_FULLY ] }
然后尝试使用以下内容访问控制器中的客户端详细信息:
$tokenManager = $this->get('fos_oauth_server.access_token_manager.default');
$accessToken = $tokenManager->findTokenByToken(
$this->get('security.token_storage')->getToken()->getToken()
);
$client = $accessToken->getClient();
然后我收到错误:
Attempted to call an undefined method named "getToken" of class "Symfony\Component\Security\Core\Authentication\Token\AnonymousToken"
答案 0 :(得分:2)
I spend a day struggling with the same situation (also Symfony 3). In the end the solution was quite simple for me.
In my security.yml I defined the following:
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
# Add your favorite authentication process here
form_login:
provider: userprovider
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
#anonymous: true #allow all requests
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
access_control:
- { path: ^/oauth/v2/token, roles: [ IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY ] }
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
There was a little error in there. I left the main in the firewall open for all urls:
main:
anonymous: ~
# activate different ways to authenticate
By removing the main and its childeren or defining a proper "pattern" which does not override the pattern of the api firewall, my OAuth2 server was working correctly.
Later I found out that the order of the firewalls is very important. Simply defining the API firewall rules before the main(default) firewall rules works like a charm. So the following is correct:
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
oauth_authorize:
pattern: ^/oauth/v2/auth
# Add your favorite authentication process here
form_login:
provider: userprovider
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
#anonymous: true #allow all requests
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false
main:
anonymous: ~
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
access_control:
- { path: ^/oauth/v2/token, roles: [ IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_FULLY ] }
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
答案 1 :(得分:0)
我想出了一种在控制器内部进行身份验证的方法,但我不确定这是否是实现我想要的最佳方式。似乎FOSOAuthServerBundle
应该能够为我做所有这些检查。
<?php
namespace ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
use Symfony\Component\Security\Core\Exception\AuthenticationExpiredException;
use FOS\OAuthServerBundle\Security\Authentication\Token\OAuthToken;
use Symfony\Component\HttpFoundation\JsonResponse;
class UserApiController extends Controller
{
/**
* @Route("/user", name="user")
*/
public function indexAction(Request $request)
{
$authenticationErrorResponse = $this->checkAuthAndGetErrorResponse($request);
if ($authenticationErrorResponse) {
return $authenticationErrorResponse;
}
// all good, now do something
}
private function checkAuthAndGetErrorResponse(Request $request)
{
$tokenManager = $this->get('fos_oauth_server.access_token_manager.default');
$bearerToken = $this->get('fos_oauth_server.server')->getBearerToken($request);
if (!$bearerToken) {
return new JsonResponse(['status' => 400, 'message' => 'Bearer token not supplied'], 400);
}
$accessToken = $tokenManager->findTokenByToken($bearerToken);
if (!$accessToken) {
return new JsonResponse(['status' => 400, 'message' => 'Bearer token not valid'], 400);
}
if ($accessToken->hasExpired()) {
return new JsonResponse(['status' => 400, 'message' => 'Access token has expired'], 400);
}
// may want to validate something else about the client, but that is beyond OAuth2 scope
//$client = $accessToken->getClient();
return null;
}
}