12

編集:執筆時点では機能していますが不完全な私自身の解決策については、以下を参照してください。いくつかの批判とフィードバックをお待ちしております。もし私が何かをまとめて、本当にしっかりしていると感じたら、同じ課題に直面している他の人のためにハウツーのブログ投稿を作成します.

私はこれに何日も苦労してきました.誰かが私が正しい道を進んでいるかどうかを教えてくれることを願っています.

現在、ユーザーを認証するために FOSUserBundle と HWIOAuthBundle を使用している FOSRestBundle Web サービスを備えたシステムがあります。

Web サービスにステートレス API キー認証を設定したいと考えています。

私はhttp://symfony.com/doc/current/cookbook/security/api_key_authentication.htmlを読みましたが、これは実装するのに十分簡単に​​思えます.UecodeApiKeyBundleもインストールしましたが、これはほとんどこの本のページの実装にすぎないようです. .

私の質問は n00b のものです...今は何ですか? 本のページとバンドルの両方で、API キーによるユーザーの認証について説明していますが、ユーザーのログイン、API キーの生成、ユーザーの登録の許可などのフローについては触れていません。アプリ開発者が使用できる登録とログアウト。/api/v1/login など。

私は登録を処理できると思います....ログインは私を混乱させます。いくつかの追加の読書に基づいて、ログインのために必要なことは次のように思えます:

  • POST リクエストを受け入れるコントローラーを api/v1/login に作成します。リクエストは { _username: foo, _password: bar } または { facebook_access_token: foo. または、Facebook のログインに /user/login/facebook などの別のアクションが必要で、HWIOAuthBundle パスにリダイレクトするだけの場合もあります。

  • リクエストに _username および _password パラメータが含まれている場合は、リクエストを login-check に転送する必要があります (これについてはよくわかりません。このフォームを自分で処理できますか? または、ユーザー名とパスワードを手動で確認する必要があります。データベース?)

  • ログイン イベント リスナーを追加し、ユーザーが正常に認証された場合は、ユーザーの API キーを生成します (もちろん、これは自分でチェックしていない場合にのみ必要です)。

  • POST リクエストの応答で API キーを返します (これは post-redirect-get 戦略を破りますが、それ以外の問題は見られません) これにより、上記のログイン チェック オプションへのリダイレクトが排除されると思います。

ご覧のとおり、私は混乱しています。これは私の最初の Symfony2 プロジェクトであり、セキュリティに関する書籍のページは単純に聞こえます...しかし、詳細の一部をごまかしているように見え、どのように進めればよいのかかなり確信が持てませんでした。

前もって感謝します!

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

編集:

関連するクックブックの記事とほぼ同じように API キー認証をインストールしました: http://symfony.com/doc/current/cookbook/security/api_key_authentication.html

ユーザーのログインを処理するために、カスタム コントローラー メソッドを作成しました。これが完璧かどうかは疑問です。改善方法についてのフィードバックをお待ちしておりますが、現在フローが機能しているため、正しい道を進んでいると確信しています。コードは次のとおりです(注意してください、まだ開発の初期段階です... 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());
    }

}

これはうまく機能しているようで、ユーザー登録も同様に処理されます。

興味深いことに、クックブックから実装した API キー認証方法は、security.yml ファイルの access_control 設定を無視しているように見えます。ソリューションなので、ユーザーの認証に使用しているパスをチェックしないように、独自の(これもやや貧弱な)ソリューションを実装しました

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

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

これを行うためのより良い方法もあると確信していますが、それが何であるかはわかりません。

4

3 に答える 3

2

/login エンドポイントが実際に必要だとは思いません。

symfony doc では、API クライアントは、API へのすべてのリクエストに (apiKey http パラメーターを介して) キーを渡す必要があります。

それがベストプラクティスであるかどうかはわかりませんが、これを行うことができます。

"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"

最良の方法は、ユーザーが Web フォーム経由で登録できるようにすることです (たとえば、ルート fos_user_register を使用)。ユーザー エンティティには、たとえば、この sha1("secret".time()) のように生成されたキーが事前入力された apikey フィールドと、キーを再生成するためのプロファイル内のボタンを含めることができます。

于 2014-09-25T07:22:06.917 に答える