容器管理的auth,处理当前登录的用户

时间:2015-09-08 09:07:55

标签: java-ee jpa dependency-injection ejb-3.0 container-managed

我一直在挖掘帖子已经太久了,头晕了,所以我希望这里的一位大师可以帮助我。

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

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

我的数据模型有JPA对象,其中一些对象已经过审核'因为他们在创建或更新时跟踪由谁

我在代码中使用@PrePersist处理程序分别在persist / update上设置createdOnupdatedOn字段,如下所示:

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

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

到目前为止,我已经能够通过这种设置,但我觉得我这样做是错的......

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

有关如何处理此问题的任何提示?这个教程的黄金链接可能解释得很好吗?谢谢你的帮助!

2 个答案:

答案 0 :(得分:1)

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

@Inject @CurrentUser Account account;

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

现在生产者的代码示例:

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中以在事务中运行逻辑。

答案 1 :(得分:0)

有一组predefined beans in CDI applications。其中 java.security.Principal表示当前调用者的身份。因此,您只需要@Inject Principal,无论您需要它。 您可能考虑的另一件事是您的特定需求是delta峰值数据模块项目的Auditing feature,它可以帮助您更多地删除自定义代码。