【问题标题】:@EJB injection in a Custom UserdetailsService (implementing Spring Security UserDetailsService)自定义 UserdetailsS​​ervice 中的@EJB 注入(实现 Spring Security UserDetailsS​​ervice)
【发布时间】:2013-05-12 21:25:00
【问题描述】:

我在我的应用程序的 JPA/EJB 3/JSF 2/Spring Security 3 中使用 glassfish 3.1.2。 我想写一个像这样的自定义 UserdetailsS​​ervice:

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

所以我试图在 MyUserDetailsS​​ervice 中注入一个 EJB,以便能够在我的 Spring Security 上下文文件中将其用作身份验证提供程序:“applicationContext-security.xml”,如下所示:

<authentication-manager>
        <authentication-provider user-service-ref="myUserDetailsService">
        </authentication-provider>
    </authentication-manager>

问题是我陷入了由 null 协作者外观引起的 NullPointerException。

我尝试了几件事,其中:

  • 使用上下文查找 EJB(例如位于 here 的那个):解决方案有效,但这不是我想要的:因为 EJB 的名称可能会被修改。

  • 将 MyUserDetailsS​​ervice 类作为 JSF 2 托管 bean,collectorurFacade 一直保持为空。

  • 将 MyUserDetailsS​​ervice 类作为 JSF 2 托管 bean 并具有 ApplicationScoped 范围,collectionurFacade 将一直保持到 null。

问题: 有什么干净的方法可以在 MyUserDetailsS​​ervice 类中注入 EJB 吗?

我知道我可以使用@Service 注释来注释我的类(参见this link),然后我将陷入我不想要的 EJB 和 Spring 的混合中

【问题讨论】:

    标签: java jakarta-ee jsf-2 spring-security ejb-3.1


    【解决方案1】:

    这是一个简单的例子,理论上应该可以工作

    1. 将其添加到您的上下文配置中
    <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

    【讨论】:

    • 你说的是applicationContext-security.xml文件吗:上下文配置,因为除此之外,我没有任何其他的spring配置文件。
    • 是的,在applicationContext-security.xml中添加
    • 我不断收到在 JNDI 环境中定义的名称为“ejb/CollaborateurFacade”的无效 bean 定义:JNDI 查找失败;嵌套异常是 javax.naming.NamingException: Lookup failed for 'ejb/CollaborateurFacade' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.impl.SerialInitContextFactory, java.naming.factory.state =com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming} [根异常是 javax.naming.NameNotFoundException: CollaborateurFacade not found]
    • 部署 EJB 后,您应该看到它注册的 JNDI 字符串,它说什么?
    • 它具有不可移植的 JNDI 名称,其中包含时代名称和 EJB 名称,这正是我不想要的。但是想出了一个可能的解决方案来解决我的问题。在答案中打印出来。
    【解决方案2】:

    我想通过以下方式解决我的问题:不重命名我的外观 (EJB),并且必须使用我在类注释 @EJB 中定义的名称来查找我的 EJB。那么我的 UserDetailsS​​ervice 就变成了这样:

    @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 = 注解中的那个,它与属性@EJB(name =

    这边:

    • 如果外观名称更改,我的 SiUserDetailsS​​ervice 中将出现编译错误,并且仅在我的 siUserDetailsS​​ervice 类中更改其名称,查找仍然有效。
    • 如果耳朵名称发生变化,我的 SiUserDetailsS​​ervice 仍然有效,因为我不使用耳朵名称进行查找。

    我的 Spring Security 上下文文件仍然是:

    <beans:bean id = "siUserDetailsService" class = "com.xxx.xxx.beans.SiUserDetailsService" />  
    
        <authentication-manager>
            <authentication-provider user-service-ref="siUserDetailsService">
            </authentication-provider>
        </authentication-manager>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-11
      • 2017-10-27
      • 2012-06-11
      • 2016-03-09
      • 2018-10-25
      • 2015-10-19
      • 2011-05-02
      • 1970-01-01
      相关资源
      最近更新 更多