0

更具体地说,我发现我正在实现一个 custom ,AuthorizingRealm它分别声明了模板方法doGetAuthenticationInfo()doGetAuthorizationInfo()返回对象。AuthenticationInfoAuthorizationInfo

但是,当我在 doGetAuthenticationInfo() 中检索 AuthenticationInfo(一个 JPA 实体)的数据时,我发现我已经拥有了必要的 AuthorizationInfo。唉,没有明显的好方法来保留这些数据,所以当授权过滤器最终在过滤器链中轮到它时,我不得不把它扔掉,只为了执行另一个 JPA 查找。

看哪:

public class CustomRealm extends AuthorizingRealm {

  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
    UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
    String username = userPassToken.getUsername()

    User user; // Contains username, password, and roles
    // Perform JPA lookup by username...
    return constructSimpleAuthenticationInfoFromUser(user);
  }

  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    // Look up user again? :(
    ...
  }
}

我考虑了多种可能性:

  1. 使用领域缓存。该应用程序将在分布式环境中运行,因此可以运行任意数量的 JVM。默认领域缓存管理器实现并不能解决所有固有问题,并且设置企业实现似乎超出了该项目的范围。
  2. 使用主题的会话。没有服务器端状态,如果可能的话,我想保持这种状态。也许您可以强制会话表现得像请求范围,但我不知道该怎么做,并且有被混淆的风险。
  3. 实现我自己的 Subject。每个请求似乎通常有一个 Subject 实例,但不清楚如何引导它,我可能会失去很多潜在的功能。
  4. 使用 Shiro ThreadContext 对象。我可以将数据作为线程本地属性附加到 ThreadContext。Servlet 容器通常遵循每个请求线程的模型,并且 Subject 实例本身似乎在这里冷静下来,等待其不可避免的垃圾收集。Shiro 似乎也自动建立和拆除上下文。但是,这方面的文档并不多,而且我很难理解源代码。

最后,默认的 WebSecurityManager 保留了 CustomRealm 的单例实例,似乎每个 JVM 一个。简单地设置一些本地实例属性不是线程安全的。

这似乎是一种常见的数据检索选项和典型的部署方案。那么,我错过了什么?

谢谢!

4

1 回答 1

1

我会选择选项 4 -ThreadLocal根据您的要求使用对象清楚地表明对象生存期必须是 http 请求。

看看这个讨论:何时以及如何使用 ThreadLocal 变量?

ThreadLocal 文档:http ://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

于 2013-04-13T08:36:13.473 回答