通过令牌/密钥进行用户和API身份验证

时间:2014-10-21 17:41:14

标签: php api rest symfony access-token

我有一个用Symfony2开发的服务器端API,现在我尝试进行身份验证。

  1. 客户端/移动设备应用必须使用API​​密钥进行身份验证
  2. 使用该应用的用户必须使用电子邮件+密码进行身份验证并获取access_token
  3. 因此我使用此防火墙和apikey身份验证器

    firewalls:
        login:
            pattern:  ^/login$
            security: false
    
        secured_area:
            pattern: ^/
            stateless: true
            simple_preauth:
                authenticator: apikey_authenticator
    

    Api Key Authenticator

    namespace Rental\APIBundle\Security;
    
    use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Core\Exception\AuthenticationException;
    use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\Security\Core\User\UserProviderInterface;
    use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
    use Symfony\Component\Security\Core\Exception\BadCredentialsException;
    
    
    class ApiKeyAuthenticator implements SimplePreAuthenticatorInterface    {
        protected $userProvider;
    
        public function __construct(ApiKeyUserProvider $userProvider)
        {
            $this->userProvider = $userProvider;
        }
    
        public function createToken(Request $request, $providerKey)
        {
    
            //$apiKey = $request->query->get('apikey');
            // use test value
            $apiKey = "234234234";
    
            if (!$apiKey) {
                throw new BadCredentialsException('No API key found');
            }
    
            return new PreAuthenticatedToken(
                'anon.',
                $apiKey,
                $providerKey
            );
        }
    
        public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
        {
            $apiKey = $token->getCredentials();
            $username = $this->userProvider->getUsernameForApiKey($apiKey);
    
            if (!$username) {
                throw new AuthenticationException(
                    sprintf('API Key "%s" does not exist.', $apiKey)
                );
            }
    
            $user = $this->userProvider->loadUserByUsername($username);
    
            return new PreAuthenticatedToken(
                $user,
                $apiKey,
                $providerKey,
                $user->getRoles()
            );
        }
    
        public function supportsToken(TokenInterface $token, $providerKey)
        {
            return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
        }
    }
    
    到目前为止,没问题。现在这个类使用以下类的方法

    namespace Rental\APIBundle\Security;
    
    use Symfony\Component\Security\Core\User\UserProviderInterface;
    use Symfony\Component\Security\Core\User\User;
    use Symfony\Component\Security\Core\User\UserInterface;
    use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
    
    class ApiKeyUserProvider implements UserProviderInterface {
        public function getUsernameForApiKey($apiKey)
        {
            // Look up the username based on the token in the database
            // use test value
            $username = "Alex";
    
            return $username;
        }
    
        public function loadUserByUsername($username)
        {
            // return User by Username
        }
    
        public function refreshUser(UserInterface $user)
        {
            // code
        }
    
        public function supportsClass($class)
        {
            return 'Symfony\Component\Security\Core\User\User' === $class;
        }
    }
    

    我的问题详情如下:

    1. 方法loadUserByUsername需要通过搜索用户名来查找用户实体。但是从这个类我没有访问数据库。我找到了使用静态方法User::find()的例子,但是没有这样的方法,而实体 - MVC的模型 - 也没有访问数据库的权限。如何让用户退出数据库?
    2. 我想首先验证APP本身的一般API访问权限,然后再用户身份验证个人信息和有限的编辑权限。当用户通过电子邮件和密码登录时,数据已保存在例如UsernamePasswortToken中,来自同一客户端的下一个呼叫如何使用access_token访问数据。该会话对这些AJAX HTTP请求没有影响。

1 个答案:

答案 0 :(得分:2)

1。 您应该为它使用依赖注入并在您的提供者中注入实体管理器。

 your_api_key_user_provider:
            class:     Rental\APIBundle\Security\ApiKeyUserProvider
            arguments: ["@doctrine.orm.entity_manager"]
 apikey_authenticator:
            class:     Rental\APIBundle\Security\ApiKeyAuthenticator
            arguments: [""@your_api_key_user_provider"]  

之后将其添加到提供者中:

    use Doctrine\ORM\EntityManager;

    class ApiKeyUserProvider implements UserProviderInterface {

        protected $em;

        public function __construct(EntityManager $em){
            $this->em = $entityManager;
        }
       //... Now you have access to database

    }

2。 Ajax可以发送cookie,php可以使用这些请求,就像正常和使用会话一样。确保您的请求是否正在发送Cookie(请参阅Why is jquery's .ajax() method not sending my session cookie?