2017-03-03 53 views
0

我是symfony的新手,我試圖獲得一個基於JWT的基本後衛身份驗證器。這項工作主要來自這裏的文章,我已經刪除了任何用戶檢查(現在):http://kolabdigital.com/lab-time/symfony-json-web-tokens-authentication-guardSymfony後衛:access_control沒有任何效果

我覺得有些東西我不明白,因爲我無法使它工作。更確切地說,即使在我實施的例外情況下,它在任何地方都可以工作。

這裏是檢查服務,基本相同的文章,沒有用戶管理,並且以位的日誌記錄:

<?php 

namespace AppBundle\Security; 

use Lexik\Bundle\JWTAuthenticationBundle\Encoder\DefaultEncoder; 
use Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor; 
use Symfony\Component\HttpFoundation\JsonResponse; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\User\UserProviderInterface; 
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; 
use Psr\Log\LoggerInterface; 

class TokenAuthenticator extends AbstractGuardAuthenticator 
{ 
    private $jwtEncoder; 
    private $logger; 

    public function __construct(DefaultEncoder $jwtEncoder, LoggerInterface $logger) 
    { 
     $this->logger = $logger; 
     $this->jwtEncoder = $jwtEncoder; 
    } 

    public function start(Request $request, AuthenticationException $authException = null) 
    { 
     $route = $request->attributes->get('_route'); 
     $url = $request->getUri(); 
     $this->logger->info($route . ' : ' . $url); 
     return new JsonResponse('Authentication required', 401); 
    } 

    public function getCredentials(Request $request) 
    { 

     if(!$request->headers->has('Authorization')) { 
      return; 
     } 

     $extractor = new AuthorizationHeaderTokenExtractor(
      'Bearer', 
      'Authorization' 
     ); 

     $token = $extractor->extract($request); 

     if(!$token) { 
      return; 
     } 

     return $token; 
    } 

    public function getUser($credentials, UserProviderInterface $userProvider) 
    { 
     $data = $this->jwtEncoder->decode($credentials); 

     if(!$data){ 
      return; 
     } 

     $username = $data['username']; 

     // TODO get user from user collection 
     $user = ['username' => $username]; 

     // Is user is encoded in token and exists, then it's fine 
     if(!$user){ 
      return; 
     } 

     return $user; 
    } 


    public function checkCredentials($credentials, UserInterface $user) 
    { 
     return true; 
    } 

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 
    { 
     return new JsonResponse([ 
      'message' => $exception->getMessage() 
     ], 401); 
    } 

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 
    { 
     return; 
    } 

    public function supportsRememberMe() 
    { 
     return false; 
    } 

} 

而且security.yml,一切排除在外,只檢查行爲。

# To get started with security, check out the documentation: 
# http://symfony.com/doc/current/security.html 
security: 

    # http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded 
    providers: 
     in_memory: 
      memory: ~ 

    firewalls: 
     # disables authentication for assets and the profiler, adapt it according to your needs 
     dev: 
      pattern: ^/(_(profiler|wdt)|css|images|js)/ 
      security: false 

################################# 
# Secured section 
# 

     # Custom authentication firewall for all request thats starts from /api 
     api: 
      pattern: ^/api 
      guard: 
       authenticators: 
        - app.token_authenticator 


################################# 
# Main Configuration 
# 

     main: 
      anonymous: ~ 
      # activate different ways to authenticate 

      # http_basic: ~ 
      # http://symfony.com/doc/current/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: ^/auth, roles: IS_AUTHENTICATED_ANONYMOUSLY } 
     #- { path: ^/version, roles: IS_AUTHENTICATED_ANONYMOUSLY } 
     #- { path: ^/api, roles: [ROLE_USER, ROLE_API_USER] } 
     - { path: ^/api, roles: IS_AUTHENTICATED_ANONYMOUSLY } 

     #- { path: ^/(css|js), roles: IS_AUTHENTICATED_ANONYMOUSLY } 
     #- { path: ^/(_wdt|_profiler), roles: IS_AUTHENTICATED_ANONYMOUSLY } 
     #- { path: ^/, roles: ROLE_USER } 

我只是把後衛上^/API的地方,放一個control_access在同一路徑上允許匿名。我期望防護服務不會在具有該配置的任何路徑上調用,但每次都會調用它。我想我錯過了一些關於它如何工作的理解。 我的理解是:

  • 訪問控制是任何事情之前
  • 如果有一個匹配的行,它需要它(第一個)
  • 如果IS_AUTHENTICATED_ANONYMOUSLY設置檢查,那麼防火牆不檢查
  • 否則,下一個檢查是防火牆的配置,其中它告訴檢查與TokenAuthenticator

最初的目的是鎖定/api,除了/api/auth/api /版本,可以無需控制地訪問。

感謝您的幫助,我認爲經過1天半的時間,我無法直截了當地思考。

回答

0

爲了記錄,我設法解決了這個問題。

首先,Guard Authenticator建立在真正的User Repository上,這不是我們想要的。我們需要使用Redis和Mongo中的UserRepository進行快速檢查。另外,我們不需要PHP會話,我們想要一個無狀態系統(只有活動令牌在redis中)。

所以我做的是爲Guard Authenticator創建一個虛擬的User對象,實現所需的接口。

在訪問時,我們通過在redis中獲取其令牌以及其他數據來檢查用戶是否已知。這些附加數據包括所需的用戶對象。

在連接上,我們實際上在數據庫中檢查用戶,如果沒問題,我們創建一個虛擬用戶對象,並用令牌將其推入到redis中。

有了這個系統,一切都很好。這不是最漂亮的解決方案,但它允許在可能有多個實例的無狀態環境中使用Guard。