2

私はあまりにも長い間投稿を掘り下げていて、めまいがするので、ここの教祖の一人がこれを手伝ってくれることを願っています.

コンテナ管理認証を使用していますが、うまく機能しています。認証するためのRealmセットアップ、web.xmlで保護されたURLのセットアップ、ログインページなどがあります。

しかし今、私は問題にぶつかっています...

データモデル用の JPA オブジェクトがあり、これらのオブジェクトの一部は、いつ作成または更新されたか、誰によって追跡されるかという点で「監査」されてます。

@PrePersist次のように、コードでハンドラーを使用して、永続化/更新のフィールドcreatedOnとフィールドをそれぞれ設定しています。updatedOn

@PrePersist
protected void onCreate() {
    this.setCreatedOn(new Date());
}

これはうまく機能しますが、ここから現在ログインしているユーザーにアクセスする方法がわかりません...createdByフィールドを設定できるようにする必要があります。

私はResteasyを使用しており、エンドポイントでログインしているユーザー名にアクセスでき、アカウント オブジェクトを取得できます。

@Path("/test")
public class TestEndpoint {
    @EJB
    AuthorizationService authService;

    @GET
    @Path("path")
    @Produces("application/json")
    @RolesAllowed("User")
    public Response test() {
        Account account = authService.getLoggedInAccount();
        return account == null ? Response.status(Status.NOT_FOUND).build() : Response.ok().entity(account).build();
    }
}

AuthorizationService は私のもので、次のようになります。

@Stateless 
@LocalBean
public class AuthorizationService {
    @Inject 
    HttpServletRequest request;

    public Account getLoggedInAccount() {
        Account result = (Account) request.getAttribute(LOGGED_IN_USER);
        if (result == null) {
            Principal principal = request.getUserPrincipal();
            if (principal != null) {
                List<Account> results = crudService.find(Account.BY_NAME, Params.of("name", principal.getName()), 0, 0);
                if (results != null && results.size() > 0) {
                    result = results.get(0);
                    request.setAttribute(LOGGED_IN_USER, result);
                }
            }
        }
        return result; 
    }
}

これは機能します。毎回DBにクエリを送信しないように、リクエスト属性にログインしたユーザーをキャッシュすることに注意してください。

今まではこの設定でうまくやっていたのですが、やり方が間違っているような気がします...

現在ログインしているユーザーの Account オブジェクトを使用して...何か... (リクエスト?) を設定し、必要な場所に挿入できるようにするグローバル インターセプト ポイント (フィルター?) を 1 つ用意したいと考えています...アプリをできるだけスケーラブルにしようとしているので、セッションを作成しないソリューションを強くお勧めします。

これを処理する方法に関するヒントはありますか?これをうまく説明しているチュートリアルへのゴールデンリンクはありますか?助けてくれてありがとう!

4

2 に答える 2

2

あなたの質問は少し不明確ですが、次のように、現在ログインしているユーザーのアカウントを CDI Bean に挿入できるようにしたいというコメントから推測します。

@Inject @CurrentUser Account account;

これには、次のものが必要です。

  • アカウント オブジェクトの作成をカスタマイズするための CDI プロデューサー
  • ログインしているユーザーに適切なアカウントを見つけることができるように、プロデューサーにプリンシパルを挿入します
  • @CurrentUserインジェクション ポイントをプロデューサーと一致させるためのカスタム修飾子
  • プロデューサーはリクエスト スコープ Bean を作成する必要があります。したがって、プロデューサーへの呼び出し (および DB への呼び出し) はキャッシュされ、リクエストごとに最初にのみ実行されます。

Producer のコード例:

public class CurrentAccountProducer {

    @Inject private Principal principal; // get logged-in principal

    /* called first time per request to find Account entity for principal
      - it will be cached and injected into @CurrentAccount @Inject points
    */
    @CurrentAccount 
    @RequestScoped
    @Produces
    public Account produceAccount() {
        if (principal == null) {
            return null; // null will be injected if user is not logged in
        } else {
            // part of your original code here...
            List<Account> results = crudService.find(Account.BY_NAME, Params.of("name", principal.getName()), 0, 0);
                if (results != null && results.size() > 0) {
                    return results.get(0);
                }
        }
    }
}

このプロデューサーは、ログインしたユーザーのアカウントまたは匿名の null を注入するために必要なすべてです。AuthorizationService次に、次のように変更できます。

@Stateless 
@LocalBean
public class AuthorizationService {
    @Inject 
    @CurrentAccount Account currentAccount;

    public Account getLoggedInAccount() {
        return currentAccount; 
    }
}

Account を TestEndpoint に直接注入し、AuthorizationService をバイパスするのと同じくらい簡単ですが、ビジネス ロジックを EJB にカプセル化して、トランザクションでロジックを実行することをお勧めします。

于 2015-09-09T11:51:24.847 に答える
1

CDI アプリケーションには、事前定義された Beanのセットがあります。その中で、java.security.Principalは現在の呼び出し元の ID を表します。したがって、必要な場所に @Inject Principal を挿入するだけです。特定のニーズに合わせて検討できるもう 1 つのことは、デルタ スパイク データ モジュール プロジェクトの監査機能です。これは、カスタム コードをさらに削減するのに役立つ可能性があります。

于 2015-09-08T11:30:23.657 に答える