web-dev-qa-db-ja.com

Slimでの認証:ミドルウェア、シングルトン、フックを組み合わせたアプローチは賢いですか?

Slimアプリケーションでユーザー認証を実行するための独自の認証コントローラーを作成しました。それは機能しますが、これがSlimが意図した方法であるかどうかはわかりません。

私の認証コントローラー_$auth_には、セッションの状態を変更する$auth->login($user, $password)$auth->logout()などのメソッドと、$auth->userIsLoggedIn()などのステータスを報告するメソッドがあります。また、リクエストがあれば、ユーザーがリクエストされたルートにアクセスできるかどうかを判断できます。

現在、Slimアプリケーションで_$auth_の単一インスタンスを2つの異なる方法で使用しています。_$app->auth_に登録されたシングルトンとして、およびすべてのルートに適用されるルートミドルウェアとしてです。したがって、Slimアプリケーションは次のようにブートストラップされます。

_// Create singleton instance of MyAuthWrapper
$app->auth = new MyAuthenticationWrapper( array() );

// Attach the same instance as middleware to all routes
$app->add( $app->auth );
_

ルート内からシングルトンインスタンスを使用しています。たとえば、ログインルートで使用しています。

_$app->post( '/login', function() use ($app)
{
    // ...
    $user = $app->auth->authenticate( $app->request()->post('username'), $app->request()->post('password') );
    // ...
}
_

そして、ユーザーが認証されていることを確認し、そうでない場合はログインページにリダイレクトするメソッドを_slim.before.dispatch_フックにアタッチすることにより、すべてのルートでミドルウェアバージョンを使用しています。これを行うために、認証ラッパーは\ Slim\Middlewareを拡張し、次のようにcallメソッドを実装します(簡略化)。

_class MyAuthenticationWrapper extends \Slim\Middleware
{
    // ... Implementation of methods such as authenticate(), isLoggedIn(), logout(), etc.

    public function call()
    {
        $app = $this->app;

        $isAuthorized = function () use ($app) {

            $hasIdentity = $this->userIsLoggedIn(); // Assume this to work
            $isAllowed = $this->userHasAccessToRequestedRoute(); // Assume this to work

            if ($hasIdentity && !$isAllowed) 
            {
                throw new Exception("You have no access to this route");
            }

            if (!$hasIdentity && !$isAllowed) 
            {
                return $app->redirect( $loginPath );
            }
        };

        $app->hook('slim.before.dispatch', $isAuthorized);

        $this->next->call();
    }
}
_

シングルトンを使用することは私にはわずかです コードの臭い ですが、$app->add( $app->auth )を使用してミドルウェアとしてシングルトンインスタンスを追加すると、明らかに汚い感じがします。そして最後に、ミドルウェアを使用してディスパッチフックへのクロージャを登録すると、この戦略全体がSlimと呼ばれるフレームワークにとってそれほど複雑ではないかと思います。しかし、私が望むことを達成するためのより簡単な、またはよりエレガントな方法があるかどうかはわかりません。

質問:私は正しい方向に進んでいますか、それともスリムがどのように機能するかについて、より複雑でない方法でこれを達成できる何かが欠けていますか?

11
Wilbo Baggins

ミドルウェアを使用して認証用のフックを登録することは、完全に正しい方向に進んでいます。それが私が採用しているアプローチであり、私が自分のライブラリに実装したアプローチです Slim Auth

Singleton を使用すると、間違いなくコードの臭いになる可能性がありますが、常にそうとは限りません。 MyAuthenticationWrapperをリファクタリングする必要があると感じた場合、それは完全にあなた次第です。カスタムクラスでミドルウェアとフックを使用する方法は、私見ですが、100%目標を達成しています。

補足:私のモットーの1つは、「機能させてからリファクタリングする」です。あなたもそこに順調に進んでいるようですので、称賛に値します。

最後に、認証と承認は複雑なトピックであり、複雑なソリューションが必要です。 Complexはnotは複雑で保守が難しいスパゲッティを意味しますが、それを正しく行うと、私が書きたいと思っていたよりも多くのコード(または私が望んでいたよりも多くの依存関係)が生じる可能性がありますComposerを介してプルします)。

[〜#〜]更新[〜#〜]

$app->authがミドルウェアの場合、はい、少し軌道に乗っています。フックを登録するためにミドルウェアを作成するというあなたの本能は死んでいますが、ミドルウェアはミドルウェアであり、そのコンテキストの外で使用すべきではありません。理想的には、ルートとミドルウェアの両方で使用できる認証クラスを作成します(または、Packagistでパッケージを見つけます)。擬似コードは次のようになります。

$auth = new Auth(); // This is *not* middleware
$app->auth = $auth;

// Login route looks the same

// Middleware
class MyAuthenticationWrapper extends \Slim\Middleware
{
    public function call()
    {
        $app = $this->app;
        $auth = $app->auth;

        // Register your hook using appropriate methods from Auth class ...

        $this->next->call();
    }
}

これが ミドルウェアの例 SlimAuthからのものです。 サンプル実装 すべてをまとめた方法を確認できます。

8
Jeremy Kendall