1

Login コントローラから Dashboard コントローラに渡したい Java User オブジェクトがあります。たくさん読んで、次の実装を試しています

public static Result authenticate(){
    Form<LoginForm> loginform = Form.form(LoginForm.class).bindFromRequest();
    if(loginform.hasErrors()){
        return badRequest(login.render(loginform));
    }
    else{
        session().clear();
        AppUser user = AppUser.getUserByEmail(loginform.get().email);
        Context.current().args.put("user", user);
        return redirect(routes.DashBoard.index());
    }

と私のダッシュボードコントローラー

public static Result index(){
    AppUser user = (AppUser) Context.current().args.get("user");
    return ok(views.html.dashboard.index.render(user));
}

これにより、nullpointerexception が発生します

これはもちろん、2 つの要求が同じ要求ではないためです。

この問題を解決する方法 遊びやすい方法 ところで、ドキュメンテーションでアクション構成について何かを見ましたが、私はそれを理解していませんでした。

4

3 に答える 3

3

私はマウノの答えに同意しますが、あなたが求めていることを実行するためにキャッシュ APIを使用できることを付け加えたいと思います。

注意すべきことの 1 つは、キャッシュが複数のユーザー間で同じであることです。キャッシュから特定のユーザー オブジェクトにアクセスできるようにするには、一意の ID が必要です。また、リクエスト間でその ID を保存します。プレイセッションはこれを行う簡単な方法です。

これが例です

public static Result authenticate(){
    Form<LoginForm> loginform = Form.form(LoginForm.class).bindFromRequest();
    if(loginform.hasErrors()){
        return badRequest(login.render(loginform));
    }
    else{
        session().clear();
        AppUser user = AppUser.getUserByEmail(loginform.get().email);


        String uuid= java.util.UUID.randomUUID().toString();
        Cache.set(uuid,user);
        //store uuid in session for extracting the proper user from cache later
        session("uuid",uuid); 

        return redirect(routes.DashBoard.index());
    }


public static Result index(){
    //gather uuid stored in session (cookies)
    String uuid = session("uuid") 
    AppUser user = Cache.get(uuid);

    return ok(views.html.dashboard.index.render(user));
}

また、これらのオブジェクトには予測可能な寿命がないため、それらの存在を確認し、場合によってはオブジェクトを再作成する必要があります。

編集: この最後のステートメントについてはよくわかりません。playframework 1 では、キャッシュ内のオブジェクトがしばらく使用されていないと削除されますが、この投稿から、playframework 2 でタイムアウトを指定しないと、デフォルトでは無期限に存続する可能性があります。これは、play API で使用されている構成/モジュールに大きく依存します。

あなたが説明した状況では、この解決策はお勧めしません。データベースは、この情報を保存するのに適した場所です。リクエストごとにユーザー データを取得する必要があります。

オブジェクトのキャッシュが可能だと言いたかっただけです。

于 2013-03-15T21:35:16.063 に答える
2

注:あなたの質問は一般的に「アクション間でオブジェクトを渡す」に関するものであるため、マイクの答えはあなたのニーズに最適です。結論は次のとおりです。キャッシュおよび/または適切に準備されたSQLステートメントを使用します(追加の関係などなしで、現時点で可能な限り小さなデータを取得することを意味します)

それが「回答を受け入れる」の最良の候補だと思います。

一方、議論から、認証のコンテキストで質問していることが明らかになってきました。私の 2cc は次のとおりです。

  • Mauno の回答では、典型的な認証アプローチについて説明しています。はい、追加のクエリが必要ですが、H2 データベースの例を埋め込みモードで使用する場合、大きな問題にはなりません。高速です。さらに、キャッシュAPIを使用して、それを少し最適化できます。
  • 実際には、このアプローチにはいくつかのセキュリティ ギャップがあります...セッション Cookie は署名されているため、理論的には操作できません...事実は変わりませんが、他の人がそれらを乗っ取って再利用することができます。最も簡単な解決策は、セッションをサーバー側 (DB またはキャッシュ) に保存することです。これにより、IP、フィンガープリントなどの詳細を比較できます。最も重要なことは、ログアウト時またはしばらく非アクティブになった後、サーバー側セッション全体を無効にすることもできます。そのため、攻撃者がセッションを取得したとしても、それを再利用することはできなくなります。もちろん、このアプローチでは追加のDBクエリが作成されますが、セキュリティとパフォーマンスのどちらが重要かを自分で選択する必要があります:)
  • 承認/認証スタックを使用する準備ができています: Play-Authenticate、ハイジャックの可能性によって警告されました。その上にサンプルを作成し、キャッシュや DB を使用してセッション処理を追加する方法を示しました: https://github. com/biesior/play-authenticate/commits/2.0.4_sessions/samples/java/play-authenticate-usage - コメントとコードの差分について、私の最新のコミットを確認してください。
于 2013-03-16T08:13:03.910 に答える
1

これを行うべきではありません (または、これを行う必要さえあります)。これは、実際に私が play を使い始めたときに考えていたことでもありました。

アクション構成は、実際には、アクセスされる特定のメソッドまたはコントローラーを保護するために使用されるものです。(ただし、他のものにも使用できます)。- ただし、ログインを実装する場合に必要です。

オブジェクトを渡す代わりにUser..ユーザーemail(ユーザー名)がセッションに配置され、後でコントローラー側とテンプレート内で取得できなくなります。(コントローラーまたはテンプレートのいずれか)。

public static Result authenticate() {
    Form<Login> loginForm = form(Login.class).bindFromRequest();
    if (loginForm.hasErrors()) {
        return badRequest(login.render(loginForm));
    } else {
        session().clear();
        session("email", loginForm.get().email);
        return redirect(
            routes.Application.index()
        );
    }
}

完全なzentask チュートリアルを確認することを強くお勧めします。ログインについてもっと知りたい場合は、zentask のページ 4を確認してください(実際の zentask の例も内部にあるplay/samples/java/zentasksので、簡単に理解できます)。

authenticate関連する部分には、独自のログインフォーム、ビュー、メソッドとクラスを備えたコントローラーの設定が含まれ、Secured実際のメソッドおよびコントローラーアクションの保護を処理します。ユーザーをデータベースに永続化することを忘れないでください-そうしないと、チェックするものがあまりありません;)

編集:

zentask チュートリアルを開くと、コントローラーが認証を必要とする場合、およびユーザー名がセッションから取得される場合の例を見ることができます。注釈を参照し@Security.Authenticated(Secured.class)くださいrequest().username()) ドキュメンテーション

@Security.Authenticated(Secured.class)
public class Projects extends Controller {
    /**
     * Display the dashboard.
     */
    public static Result index() {
        return ok(
            dashboard.render(
                Project.findInvolving(request().username()),
                Task.findTodoInvolving(request().username()),
                User.find.byId(request().username())
            )
        );
    }

...

たとえば、メソッド自体は、モデルをレンダリングするためにデータベースからUser.find.byId(request().username())完全にロードされます。User:)

しかし、私が提供したチュートリアル、その完全な例を読んでください。乾杯。

于 2013-03-15T20:11:57.270 に答える