Symfony2 - 用户名&具有自定义身份验证器的Twig模板中的角色

时间:2014-08-19 13:51:05

标签: php security symfony authentication twig

我正在使用自定义身份验证器来使用第三方服务验证登录凭据。

当我尝试在树枝内访问{{ app.user }}时,它未定义。如果我访问{{ app.security.token.user }},我会将用户名作为字符串。

我需要访问当前用户的角色,但由于app.user未设置,我不知道如何执行此操作。

在分析器中,将显示用户及其角色,因此它们必须在某处可用。

任何想法为什么它们可能不可用,或者我如何才能访问这些信息?

Authenticator Class

<?php

namespace Client\AdminBundle\Security;


use Doctrine\ORM\EntityManager;
use Client\AdminBunde\Entity\User;
use Client\AdminBunde\Exception\RuntimeException;
use Client\AdminBunde\Entity\Client;
use Client\AdminBunde\Entity\ClientRepository;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Message\ResponseInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;

class CustomAuthenticator implements SimpleFormAuthenticatorInterface
{
    /**
     * @var array
     */
    protected $rolesMap;

    /**
     * @var ClientRepository
     */
    protected $clientRepository;

    /**
     * @var EntityManager
     */
    private $entityManager;

    /**
     * @param array            $rolesMap
     * @param ClientRepository $clientRepository
     * @param EntityManager    $entityManager
     */
    public function __construct( $rolesMap, ClientRepository $clientRepository, EntityManager $entityManager )
    {
        $this->rolesMap         = $rolesMap;
        $this->clientRepository = $clientRepository;
        $this->entityManager    = $entityManager;
    }


    /**
     * @param TokenInterface        $token
     * @param UserProviderInterface $userProvider
     * @param                       $providerKey
     *
     * @throws RuntimeException if response is not set by the time needed
     *
     * @return UsernamePasswordToken
     */
    public function authenticateToken( TokenInterface $token, UserProviderInterface $userProvider, $providerKey )
    {
        $username = $token->getUsername();
        $password = $token->getCredentials();
        $user     = new User;
        $user->setUsername( $username )
             ->setPassword( $password );

        $uri = 'http://example.com/sso-integration/auth' .
               '?userId=' . urlencode( $user->getUsername() ) .
               "&passwordHash=" . urlencode( $user->getPassword() );

        try {
            $response = $this->guzzleGet( $uri );
        } catch ( RequestException $e ) {
            $reason = @$e->getResponse()->getReasonPhrase();
            if ( ! empty( $reason )) {
                throw new AuthenticationException( 'Unable to login.  ' . $reason . '.' );
            }
        } catch ( \Exception $e ) {
            throw new AuthenticationException( 'Unable to login.  Please try again.' );
        }

        if (empty( $response )) {
            throw new RuntimeException( 'No response' );
        }

        if (200 != $response->getStatusCode()) {
            throw new AuthenticationException(
                'There was a problem connecting to the authentication service.  Please try again.'
            );
        }

        $responseJson = @$response->json();

        if (empty( $responseJson['status'] )) {
            throw new AuthenticationException(
                'There was a problem connecting to the authentication service.  Please try again.'
            );
        }

        if ('OK' !== $responseJson['status']) {
            $msg = ! empty( $responseJson['message'] ) ? $responseJson['message'] : 'Incorrect credentials';
            throw new AuthenticationException( $msg );
        }

        if (empty( $responseJson['roles'] )) {
            throw new AuthenticationException( 'Authenticated, but with no role.  Please try again.' );
        }

        $returnedRoles = $responseJson['roles'];
        if ( ! is_array( $returnedRoles )) {
            $returnedRoles = [ $returnedRoles ];
        }

        $roles = [ ];
        foreach ($returnedRoles as $role) {
            if ( ! empty( $this->rolesMap[$role] )) {
                $roles[] = $this->rolesMap[$role];
            }
        }

        if (empty( $roles )) {
            throw new AuthenticationException( 'Authenticated, but with no role.  Please try again.' );
        }

        $client = @$this->clientRepository->findOneByUsername( $username );

        if (empty( $client )) {
            $client = new Client;
            $client->setUsername( $username )
                   ->setName( $username );
            $this->entityManager->persist( $client );
            $this->entityManager->flush();
        }

        $user->setClient( $client );
        $user->setRoles( $roles );

        $token = new ClientUsernamePasswordToken(
            $user->getUsername(),
            $user->getPassword(),
            $providerKey,
            $user->getRoles()
        );

        return $token;
    }

    /**
     * Indicates if this class can authenticate a given token
     *
     * @param TokenInterface $token
     * @param                $providerKey
     *
     * @return bool
     */
    public function supportsToken( TokenInterface $token, $providerKey )
    {
        return $token instanceof ClientUsernamePasswordToken;
    }

    /**
     * Creates the user token with user's login credentials
     *
     * @param Request $request
     * @param string  $username
     * @param string  $password
     * @param         $providerKey
     *
     * @return UsernamePasswordToken
     */
    public function createToken( Request $request, $username, $password, $providerKey )
    {
        return new ClientUsernamePasswordToken( $username, $password, $providerKey );
    }

    /**
     * @param $uri
     *
     * @return ResponseInterface
     */
    protected function guzzleGet( $uri )
    {
        $guzzleClient = new GuzzleClient();
        /** @noinspection PhpVoidFunctionResultUsedInspection */
        $response = $guzzleClient->get( $uri );

        return $response;
    }
}

令牌类

<?php
/**
 * Created by PhpStorm.
 * User: toby
 * Date: 17/07/2014
 * Time: 23:51
 */

namespace Client\AdminBundle\Security;


use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

class ClientUsernamePasswordToken extends UsernamePasswordToken
{
} 

services.yml

parameters:
    client.security.authenticator.class: Client\AdminBundle\Security\ClientAuthenticator
    client.form.type.client.class: Client\AdminBundle\Form\Type\ClientType
    client.form.type.client_own.class: Client\AdminBundle\Form\Type\ClientOwnType
    client.form.type.app.class: Client\AdminBundle\Form\Type\AppType
    client.form.type.gallery.class: Client\AdminBundle\Form\Type\GalleryType
    client.form.type.colour.class: Client\AdminBundle\Form\Type\ColourType
    client.form.type.image.class: Client\AdminBundle\Form\Type\ImageType
    client.image: Client\AdminBundle\Service\Image
    client.image.sizes: []
    client.image.upload_subscriber.class: Client\AdminBundle\EventListener\ImageUploadDoctrineEventListener
    client.cdn.aws_s3.class: Client\AdminBundle\File\AWSS3
    client.event_listener.new_image.class: Client\AdminBundle\EventListener\NewImageEventListener
    client.file.path_calculator.class: Client\AdminBundle\File\PathCalculator
    client.eventlistener.admin_cache_prevention.class: Client\AdminBundle\EventListener\AdminCachePreventionEventSubscriber
    client.eventlistener.varnish_cache_clear.class: Client\AdminBundle\EventListener\VarnishCacheClearListener

services:
    client.security.authenticator:
        class: %client.security.authenticator.class%
        arguments: [%client.user_roles%, @client.repository.client, @doctrine.orm.default_entity_manager]

    client.form.type.client:
        class: %client.form.type.client.class%
        tags:
            - { name: form.type, alias: client }

    client.form.type.client_own:
        class: %client.form.type.client_own.class%
        tags:
            - { name: form.type, alias: client_own }

    client.form.type.app:
        class: %client.form.type.app.class%
        calls:
            - [setImageService, [@client.image]]
        tags:
            - { name: form.type, alias: app }

    client.form.type.gallery:
        class: %client.form.type.gallery.class%
        calls:
            - [setAppRepository, [@client.repository.app]]
            - [setImageService, [@client.image]]
        tags:
            - { name: form.type, alias: gallery }

    client.form.type.colour:
        class: %client.form.type.colour.class%
        tags:
            - { name: form.type, alias: colour }

    client.form.type.image:
        class: %client.form.type.image.class%
        calls:
            - [setImageService, [@client.image]]
        tags:
            - { name: form.type, alias: image }

    client.image:
        class: %client.image%
        calls:
            - [setRouter, [@router.default]]
            - [setEventDispatcher, [@event_dispatcher]]
            - [setCdn, [@client.cdn.aws_s3]]
            - [setSizes, [%client.image.sizes%]]
            - [setImageQuality, [%client.images.resize_quality%]]

    client.image.upload_subscriber:
        class: %client.image.upload_subscriber.class%
        calls:
            - [setImageService, [@client.image]]
            - [setEventDispatcher, [@event_dispatcher]]
            - [setPathCalculator, [@client.file.path_calculator]]
            - [setLogger, [@monolog.logger]]
        tags:
            - { name: doctrine.event_listener, event: uploadablePostFileProcess }

    client.cdn.aws_s3:
        class: %client.cdn.aws_s3.class%
        arguments: [@aws_s3, %aws_s3_images_bucket%, %aws_cloudfront_domains%]
        calls:
            - [setRequestStack, [@request_stack]]

    client.event_listener.new_image:
        class: %client.event_listener.new_image.class%
        calls:
            - [setCdn, [@client.cdn.aws_s3]]
            - [setPathCalculator, [@client.file.path_calculator]]
        tags:
            - { name: kernel.event_subscriber }

    client.file.path_calculator:
        class: %client.file.path_calculator.class%
        calls:
            - [setWebRoot, [%webroot%]]

    client.eventlistener.admin_cache_prevention:
        class: %client.eventlistener.admin_cache_prevention.class%
        tags:
            - { name: kernel.event_subscriber }

    client.eventlistener.varnish_cache_clear:
        class: %client.eventlistener.varnish_cache_clear.class%
        calls:
            - [setContainer, [@service_container]]
            - [setRouter, [@router.default]]
        tags:
            - { name: doctrine.event_subscriber }

security.yml

security:
    providers:
        in_memory:
            memory:
                users:
                    # Users now handled by Client SSO integration
#                    ryan:  { password: ryanpass, roles: 'ROLE_USER' }
#                    admin: { password: kittens, roles: 'ROLE_ADMIN' }
#                    disco-superuser: { password: flxpwd, roles: 'ROLE_ADMIN' }

    role_hierarchy:
        #...

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        secured_area:
            pattern: ^/
            anonymous: ~
            simple_form:
                authenticator: client.security.authenticator
                login_path: login
                check_path: login_check
                csrf_provider: form.csrf_provider
                default_target_path:  login_redirect
            remember_me:
                key:      "%secret%"
                lifetime: 31536000 # 365 days in seconds
                path:     /
                domain:   ~ # Defaults to the current domain from $_SERVER
            logout:
                path:   logout
                target: login

    access_control:
        # ...

    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

3 个答案:

答案 0 :(得分:1)

如果您有权访问用户名,那么您也可以访问角色,因为{{ app.security.token }}正在返回TokenInterface(请参阅Api参考)。然后,您可以在方法中的模板{{ app.security.token.getRoles() }}$token->getUsername();中获得角色。

答案 1 :(得分:0)

您尝试访问的页面是否受防火墙保护?默认情况下,只有这样的页面才能从模板访问用户。

答案 2 :(得分:0)

{{ app.security.token.user }}来自安全上下文。 {{ app.user }}来自用户提供商。它们可以被映射。您是否正确设置了the user provider?我看到你配置了User个实体,所以在你的情况下app/config/security.yml应该有类似的东西我猜:

security:
    providers:
        main:
            entity:
                class: Client\AdminBunde\Entity\User
                property: username