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

3

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

  1. 客户端/移动设备应用程序必须使用API密钥进行身份验证
  2. 使用应用程序的用户必须使用电子邮件+密码进行身份验证,并获得访问令牌

因此,我使用这个防火墙和apikey验证器。

firewalls:
    login:
        pattern:  ^/login$
        security: false

    secured_area:
        pattern: ^/
        stateless: true
        simple_preauth:
            authenticator: apikey_authenticator

API密钥认证器

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个回答

2

1. 对于IT技术,你应该使用依赖注入,并在提供程序中注入实体管理器。

 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(参见为什么jquery的.ajax()方法没有发送我的会话cookie?)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接