2

我已经在帖子中挖掘了太久并且头晕目眩,所以我希望这里的一位大师可以帮助我解决这个问题。

我正在使用容器管理的身份验证,它运行良好。我有我的 Realm 设置来进行身份验证,在 web.xml 中设置受保护的 url,有一个登录页面等。

但现在我遇到了一个问题......

我的数据模型有 JPA 对象,其中一些对象经过“审核”,因为它们跟踪它们的创建或更新时间以及由谁创建或更新。

@PrePersist在我的代码中使用一个处理程序来分别设置持久/更新的createdOn和字段,如下所示:updatedOn

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

这很好用,但我错过了如何从这里访问当前登录的用户......我需要它才能设置该createdBy字段。

我正在使用Resteasy并且在我的端点中我确实可以访问登录的用户名并且能够获取我的 Account 对象:

@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; 
    }
}

这行得通。请注意,我将登录用户缓存在请求属性上,因此我不会每次都将查询发送到数据库。

到目前为止,我已经能够通过这个设置,但我觉得我做这一切都错了......

我想有一个全局拦截点(过滤器?),我用当前登录的用户的 Account 对象填充......某物......(请求?)然后能够在需要的地方注入它......我我会非常喜欢不创建会话的解决方案,因为我正在尝试使应用程序尽可能可扩展。

有关如何处理此问题的任何提示?可能很好地解释了这一点的教程的黄金链接?感谢您的帮助!

4

2 回答 2

2

您的问题有点不清楚,但我想从评论中您希望能够将当前登录用户的帐户注入您的 CDI bean,如下所示:

@Inject @CurrentUser Account account;

为此,您需要:

  • 用于自定义帐户对象创建的 CDI 生产者
  • 将主体注入生产者,以便您可以为登录用户找到合适的帐户
  • 自定义@CurrentUser限定符以将您的注入点与生产者匹配
  • 生产者应该创建一个请求范围的bean - 因此对生产者(然后是数据库)的调用被缓存并仅在每个请求第一次执行

现在生产者的代码示例:

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代表当前调用者的身份。因此,您只需在需要的地方@Inject Principal 即可。针对您的特定需求,您可能会考虑的另一件事是增量峰值数据模块项目的审计功能,它可能会帮助您进一步削减自定义代码。

于 2015-09-08T11:30:23.657 回答