我在我的应用程序中使用了JPA / EJB 3 / JSF 2 / Spring Security 3中的glassfish 3.1.2。 我想写一个像这样的自定义UserdetailsService:
import org.apache.log4j.Logger;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class MyUserDetailsService implements UserDetailsService {
private static final Logger logger = Logger.getLogger(MyUserDetailsService.class);
@EJB
private CollaborateurFacadeLocal collaborateurFacade;
@Override
public UserDetails loadUserByUsername(String userName) {
Collaborateur collab = getUser(userName);
if (collab == null) {
throw new UsernameNotFoundException(userName + " not found");
}
User user = new User(collab);
if (user == null) {
throw new UsernameNotFoundException(userName + " not found");
}
return user;
}
}
所以我试图在我的MyUserDetailsService中注入一个EJB,以便能够在我的Spring Security上下文文件中将它用作身份验证提供程序:“applicationContext-security.xml”,如下所示:
<authentication-manager>
<authentication-provider user-service-ref="myUserDetailsService">
</authentication-provider>
</authentication-manager>
问题是我陷入了由null collaborateurFacade引起的NullPointerException。
我尝试了几件事,其中包括:
使用上下文(如选址here)来释放EJB:解决方案有效,但这不是我想要的:因为EJB的名称可能会被修改。
将MyUserDetailsService类作为JSF 2托管bean,将collaborateurFacade设置为null。
将MyUserDetailsService类作为JSF 2托管bean并使用ApplicationScoped范围,将collaborateurFacade设置为null。
问题: 是否有任何干净的方法可以在MyUserDetailsService类中注入EJB?
我知道我可以用@Service注释来注释我的类(参见this link),然后我会混合使用EJB和Spring,我不想要
答案 0 :(得分:2)
这是一个简单的例子,理论上应该起作用
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name=”alwaysUseJndiLookup” value=”true” />
</bean>
2。我猜你有一个本地EJB,因为你尝试使用@EJB注释。您必须为EJB提供映射名称。例如,对于无国籍用户
@Stateless(name = "ejb/CollaborateurFacade", mappedName = "ejb/CollaborateurFacade")
class CollaboratorFacade {}
3。在spring bean中使用mappedName
@EJB(mappedName = "ejb/CollaborateurFacade")
private CollaborateurFacadeLocal collaborateurFacade;
我知道你写道,EJB的名称是一个需要修改的主题,但我不知道你怎么能避免这样做。
还有另一种可能的解决方案(基于xml!)http://czetsuya-tech.blogspot.ca/2012/05/how-to-call-stateless-ejb-from-spring.html
答案 1 :(得分:1)
我想通过以下方式解决我的问题:不要重命名我的外观(EJB),并且必须使用我在类注释@EJB中定义的名称查找我的EJB。然后我的UserDetailsService变成这样:
@EJB(name = "collaborateurFacadeLocal", beanInterface = CollaborateurFacadeLocal.class)
public class SiUserDetailsService implements UserDetailsService {
private static final Logger logger = Logger.getLogger(SiUserDetailsService.class);
private CollaborateurFacadeLocal collaborateurFacade;
private static final String COLLABORATEUR_EJB_LOOKUP_PATH = "java:comp/env/collaborateurFacadeLocal";
@Override
public UserDetails loadUserByUsername(String userName) {
User user;
Collaborateur collab = getUser(userName);
if (collab == null) {
throw new UsernameNotFoundException(userName + " not found");
}
user = new User(collab);
if (user == null) {
throw new UsernameNotFoundException(userName + " not found");
}
return user;
}
private Collaborateur getUser(String userName) {
try {
InitialContext initialContext = new InitialContext();
collaborateurFacade = (CollaborateurFacadeLocal) initialContext.lookup(COLLABORATEUR_EJB_LOOKUP_PATH);
return collaborateurFacade.findUserByUserName(userName);
} catch (NamingException ex) {
logger.error("Could not lookup for EJB CollaborateurFacadeLocal with lookup path " + COLLABORATEUR_EJB_LOOKUP_PATH);
}
return null;
}
}
java:comp / env / collaborateurFacadeLocal中的collaborateurFacadeLocal是@EJB中的一个(name = annotation,将其与@EJB属性相关联(name =
这样:
我的Spring Security上下文文件仍然是:
<beans:bean id = "siUserDetailsService" class = "com.xxx.xxx.beans.SiUserDetailsService" />
<authentication-manager>
<authentication-provider user-service-ref="siUserDetailsService">
</authentication-provider>
</authentication-manager>