使用FOSUserBundle(和HWIOauthBundle)在Symfony2中进行简单的API密钥验证,填补空白

时间:2022-10-16 13:36:59

Edit: See below for my own solution, which is, at the time of writing, functioning but imperfect. Would love some criticism and feedback, if I get something put together that I feel is really solid then I'll make a howto blog post for other people facing the same challenge.

编辑:请参阅下面的我自己的解决方案,在撰写本文时,它正在运作但不完美。我会喜欢一些批评和反馈,如果我得到一些我认为非常可靠的东西,那么我会为面临同样挑战的其他人制作一个howto博客文章。

I've been struggling with this for days, and I'm hoping someone can let me know if I'm on the right path.

几天来我一直在努力奋斗,如果我走在正确的道路上,我希望有人能告诉我。

I have a system with a FOSRestBundle webservice in which I'm currently using FOSUserBundle and HWIOAuthBundle to authenticate users.

我有一个带有FOSRestBundle webservice的系统,我正在使用FOSUserBundle和HWIOAuthBundle来验证用户。

I would like to set up stateless api key authentication for the webservice.

我想为webservice设置无状态api密钥身份验证。

I've read through http://symfony.com/doc/current/cookbook/security/api_key_authentication.html and this seems simple enough to implement, I've also installed UecodeApiKeyBundle which seems to be mostly just an implementation of this book page.

我已经阅读了http://symfony.com/doc/current/cookbook/security/api_key_authentication.html,这看起来很简单,我已经安装了UecodeApiKeyBundle,这似乎只是本书页面的一个实现。

My question is a n00b one...what now? The book page and bundle both cover authenticating a user by API key, but don't touch on the flow of logging users in, generating API keys, allowing users to register, etc. What I would really like is simple API endpoints for login, register, and logout that my app developers can use. Something like /api/v1/login, etc.

我的问题是n00b ...现在怎么办?书籍页面和捆绑包都包括通过API密钥对用户进行身份验证,但不要触及记录用户的流程,生成API密钥,允许用户注册等。我真正想要的是用于登录的简单API端点,注册,注销我的应用开发者可以使用。像/ api / v1 / login等等。

I think I can handle registration....login is confusing me though. Based upon some additional reading, it seems to me like what I need to do for login is this:

我想我可以处理注册....虽然登录让我感到困惑。基于一些额外的阅读,在我看来,我需要做的登录是这样的:

  • Create a controller at api/v1/login that accepts POST requests. The request will either look like { _username: foo, _password: bar } or something like { facebook_access_token: foo. Alternately, the facebook login could require a different action, like /user/login/facebook, and just redirect to the HWIOAuthBundle path }.

    在api / v1 / login创建一个接受POST请求的控制器。请求看起来像{_username:foo,_ password:bar}或类似{facebook_access_token:foo。或者,facebook登录可能需要不同的操作,例如/ user / login / facebook,并且只需重定向到HWIOAuthBundle路径}。

  • If the request contains _username and _password parameters, then I need to forward the request to login-check (I'm not sure about this one. Can I just process this form myself? Or, should I manually check the username and password against the database?)

    如果请求包含_username和_password参数,那么我需要将请求转发到login-check(我不确定这个。我可以自己处理这个表单吗?或者,我应该手动检查用户名和密码数据库?)

  • Add a login event listener, if user authenticated successfully, generate an api key for the user (This is only necessary if I'm not checking it myself, of course)

    添加一个登录事件监听器,如果用户认证成功,则为用户生成一个api密钥(当然,如果我自己不检查它,这是必要的)

  • Return the API Key in the response of the POST request (This breaks the post-redirect-get strategy, but otherwise I don't see any issues with it) I think this eliminates the redirect to login-check option I listed above.

    在POST请求的响应中返回API密钥(这会破坏post-redirect-get策略,但是我没有看到任何问题)我认为这消除了上面列出的重定向登录检查选项。

As you can probably see I'm confused. This is my first Symfony2 project, and the book pages on Security sound simple...but seem to gloss over some of the details and it's left me quite unsure of what way to proceed.

你可能会看到我很困惑。这是我的第一个Symfony2项目,关于安全性的书页很简单......但似乎掩盖了一些细节,这让我不确定要采取什么方式。

Thanks in advance!

提前致谢!

=============================================================

================================================== ===========

Edit:

编辑:

I've installed a API Key Authentication pretty much identically to the relevant cookbook article: http://symfony.com/doc/current/cookbook/security/api_key_authentication.html

我已经安装了API密钥身份验证,与相关的相关菜谱文章完全相同:http://symfony.com/doc/current/cookbook/security/api_key_authentication.html

To handle user's logging in, I've created a custom controller method. I doubt that this is perfect, I would love to hear some feedback on how it can be improved, but I do believe that I'm on the right path as my flow is now working. Here's the code (Please note, still early in development...I haven't looked at Facebook login yet, only simple username/password login):

为了处理用户的登录,我创建了一个自定义控制器方法。我怀疑这是完美的,我很想听到一些关于它如何改进的反馈,但我相信我正在走上正确的道路,因为我的流程正在发挥作用。这是代码(请注意,还在开发的早期......我还没有看过Facebook登录,只有简单的用户名/密码登录):

class SecurityController extends FOSRestController
{

    /**
     * Create a security token for the user
     */

    public function tokenCreateAction()
    {
        $request = $this->getRequest();

        $username = $request->get('username',NULL);
        $password = $request->get('password',NULL);

        if (!isset($username) || !isset($password)){
            throw new BadRequestHttpException("You must pass username and password fields");
        }

        $um = $this->get('fos_user.user_manager');
        $user = $um->findUserByUsernameOrEmail($username);

        if (!$user instanceof \Acme\UserBundle\Entity\User) {
            throw new AccessDeniedHttpException("No matching user account found");
        }

        $encoder_service = $this->get('security.encoder_factory');
        $encoder = $encoder_service->getEncoder($user);
        $encoded_pass = $encoder->encodePassword($password, $user->getSalt());

        if ($encoded_pass != $user->getPassword()) {
            throw new AccessDeniedHttpException("Password does not match password on record");
        }


        //User checks out, generate an api key
        $user->generateApiKey();
        $em = $this->getDoctrine()->getEntityManager();
        $em->persist($user);
        $em->flush();

        return array("apiKey" => $user->getApiKey());
    }

}

This seems to work pretty well, and user registration will be handled similarly.

这似乎工作得很好,用户注册将以类似方式处理。

Interestingly to me, the api key authentication method I implemented from the cookbook appears to ignore the access_control settings in my security.yml file, in the cookbook they outline how to only generate the token for a specific path, but I didn't like that solution, so I've implemented my own (also somewhat poor) solution to not check the path I'm using to authenticate users

有趣的是,我从cookbook实现的api密钥身份验证方法似乎忽略了我的security.yml文件中的access_control设置,在cookbook中他们概述了如何只生成特定路径的令牌,但我不喜欢解决方案,所以我实现了自己的(也有点差)解决方案,不检查我用来验证用户的路径

api_login:
    pattern: ^/api/v1/user/authenticate$
    security: false

api:
    pattern: ^/api/*
    stateless: true
    anonymous: true
    simple_preauth:
        authenticator: apikey_authenticator

I'm sure there's a better way to do this too, but again...not sure what it is.

我确信有更好的方法可以做到这一点,但再次......不确定它是什么。

3 个解决方案

#1


3  

You are trying to implement stateless authentication with username and login. This is pretty much what the Oauth2 authentication passsword grant does. This is pretty standard, so instead of trying to implement it yourself i'd recommend you use a Bundle for that, for example the FOSOauthServerBundle. It can use FOSUserBundle as its user provider and would be cleaner, more secured and easier to use than a home-made solution.

您正尝试使用用户名和登录实现无状态身份验证。这几乎就是Oauth2身份验证密码授权所做的事情。这是非常标准的,所以不要试图自己实现它,我建议你使用Bundle,例如FOSOauthServerBundle。它可以使用FOSUserBundle作为其用户提供商,并且比自制解决方案更清洁,更安全,更易于使用。

To register user, your can create a register action in your API (e.g., in a REST API I'd use POST - api/v1/users), and in the controller method copy and past the code from the FOSUserBundle:RegistrationController (of course adapt it for your needs).

要注册用户,你可以创建你的API在寄存器中的动作(例如,在REST API我会使用POST - API / V1 /用户),并在控制器方法复制和过去从FOSUserBundle代码:这个RegistrationController(中当然根据您的需要调整它)。

I did that in a REST API, it worked like a charm.

我在REST API中做到了这一点,它就像一个魅力。

#2


2  

I don't think you actually really need a /login endpoint.

我认为你真的不需要/ login端点。

In the symfony doc, the api client is required to pass it's key (via apiKey http parameter) to every request to the API.

在symfony doc中,api客户端需要将其密钥(通过apiKey http参数)传递给API的每个请求。

I am not sure it's in the best practice, but you could do this.

我不确定这是最好的做法,但你可以做到这一点。

"The book page and bundle both cover authenticating a user by API key, but don't touch on the flow of logging users in, generating API keys, allowing users to register"

The best is to allow your users to register via a web form (for example with the route fos_user_register). User entity could have an apikey field, pre-populated with a key generated like this sha1("secret".time()) for example, and a button in their profile to regenerate the key.

最好的方法是允许用户通过Web表单注册(例如使用路由fos_user_register)。用户实体可以有一个apikey字段,例如,预先填充了像sha1(“secret”.time())生成的密钥,并在其配置文件中有一个按钮来重新生成密钥。

#3


-1  

Class GenearteToken extends FOSRestController
{

     public getTokenAction(Request $request){

          $apiKey = $request->query->get('apikey');
          return $apiKey;
      }


}

#1


3  

You are trying to implement stateless authentication with username and login. This is pretty much what the Oauth2 authentication passsword grant does. This is pretty standard, so instead of trying to implement it yourself i'd recommend you use a Bundle for that, for example the FOSOauthServerBundle. It can use FOSUserBundle as its user provider and would be cleaner, more secured and easier to use than a home-made solution.

您正尝试使用用户名和登录实现无状态身份验证。这几乎就是Oauth2身份验证密码授权所做的事情。这是非常标准的,所以不要试图自己实现它,我建议你使用Bundle,例如FOSOauthServerBundle。它可以使用FOSUserBundle作为其用户提供商,并且比自制解决方案更清洁,更安全,更易于使用。

To register user, your can create a register action in your API (e.g., in a REST API I'd use POST - api/v1/users), and in the controller method copy and past the code from the FOSUserBundle:RegistrationController (of course adapt it for your needs).

要注册用户,你可以创建你的API在寄存器中的动作(例如,在REST API我会使用POST - API / V1 /用户),并在控制器方法复制和过去从FOSUserBundle代码:这个RegistrationController(中当然根据您的需要调整它)。

I did that in a REST API, it worked like a charm.

我在REST API中做到了这一点,它就像一个魅力。

#2


2  

I don't think you actually really need a /login endpoint.

我认为你真的不需要/ login端点。

In the symfony doc, the api client is required to pass it's key (via apiKey http parameter) to every request to the API.

在symfony doc中,api客户端需要将其密钥(通过apiKey http参数)传递给API的每个请求。

I am not sure it's in the best practice, but you could do this.

我不确定这是最好的做法,但你可以做到这一点。

"The book page and bundle both cover authenticating a user by API key, but don't touch on the flow of logging users in, generating API keys, allowing users to register"

The best is to allow your users to register via a web form (for example with the route fos_user_register). User entity could have an apikey field, pre-populated with a key generated like this sha1("secret".time()) for example, and a button in their profile to regenerate the key.

最好的方法是允许用户通过Web表单注册(例如使用路由fos_user_register)。用户实体可以有一个apikey字段,例如,预先填充了像sha1(“secret”.time())生成的密钥,并在其配置文件中有一个按钮来重新生成密钥。

#3


-1  

Class GenearteToken extends FOSRestController
{

     public getTokenAction(Request $request){

          $apiKey = $request->query->get('apikey');
          return $apiKey;
      }


}