我已经实现了一个 Jaas 登录模块,以执行身份验证。我必须访问数据库以检索此模块中的用户/通行证信息。
在同一个项目中,存在一些 DAO bean 的实现,但无法从 jaas 登录模块访问 Spring 上下文来检索 DAO bean。
¿ 任何人都可以帮助我吗?
我正在使用 Spring Security 将 Jaas 集成到我的应用程序中。
我已经实现了一个 Jaas 登录模块,以执行身份验证。我必须访问数据库以检索此模块中的用户/通行证信息。
在同一个项目中,存在一些 DAO bean 的实现,但无法从 jaas 登录模块访问 Spring 上下文来检索 DAO bean。
¿ 任何人都可以帮助我吗?
我正在使用 Spring Security 将 Jaas 集成到我的应用程序中。
如果您有权访问 LoginModule,只需添加接口 ApplicationContextAware 和 LoginModule 的 bean 定义。当应用程序启动时,上下文将在模块中可用。
public class LoginModule implements ApplicationContextAware {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
接口的 Javadoc: http: //static.springsource.org/spring/docs/3.0.5.RELEASE/api/org/springframework/context/ApplicationContextAware.html
JAAS 和登录模块在主要 Spring 框架上下文旁边加载和初始化。这是由 java 平台完成的工作,它不知道您打算使用 Spring。出于这个原因,您需要通过某种单例或持有者将 Spring 上下文桥接到您的登录模块。更优雅的方法是实现你自己的AuthenticationProvider
,它是合法的 spring bean。
为了解决目的和其他有兴趣获取 Spring 应用程序上下文而不显式访问它的人,我想提供一个示例。请记住,虽然这种方式是可移植的,但您可能会遇到由于类加载器可见性导致多个单例而引起的各种麻烦。在任何应用程序服务器或 servlet 容器中运行此代码时要小心。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.util.Optional;
public class SpringContextHolder implements ApplicationContextAware, InitializingBean {
private static SpringContextHolder INSTANCE;
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public Optional<ApplicationContext> getApplicationContext() {
return Optional.ofNullable(applicationContext);
}
public static Optional<SpringContextHolder> getInstance() {
return Optional.ofNullable(INSTANCE);
}
@Override
public void afterPropertiesSet() throws Exception {
INSTANCE = this;
}
}
然后,您的登录模块可以通过单例访问应用程序上下文:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.spi.LoginModule;
import java.util.Map;
public class TokenLoginModule implements LoginModule {
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) {
ApplicationContext context = SpringContextHolder.getInstance()
.flatMap(SpringContextHolder::getApplicationContext)
.orElseThrow(() -> new RuntimeException("Unable to locate Spring context"));
// lookup via context.getBean or just store it as a field
}
}