创建bean期望的单个匹配bean但发现2时出现Spring安全性错误

时间:2016-03-25 06:14:28

标签: spring spring-security jersey

我正在尝试在Spring应用程序中使用My Rest简单Web服务实现Spring安全性。我尝试了一些基本的身份验证并且它工作正常。下一步我尝试创建自定义过滤器我的security-context.xml是

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd">



    <!-- SPRING SECURITY SETUP -->

    <beans:bean id="userDao" class="com.cheasyy.cofinding.dao.UserDAO">
    </beans:bean>

    <beans:bean id="passwordEncoder"
        class="org.springframework.security.crypto.password.StandardPasswordEncoder">
        <beans:constructor-arg value="ThisIsASecretSoChangeMe" />
    </beans:bean>

    <security:authentication-manager id="authenticationManager">
        <security:authentication-provider
            user-service-ref="userDao">
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <security:http realm="Protected API" use-expressions="true"
        auto-config="false" create-session="stateless" entry-point-ref="unauthorizedEntryPoint"
        authentication-manager-ref="authenticationManager">
        <security:custom-filter ref="authenticationTokenProcessingFilter"
            position="FORM_LOGIN_FILTER" />

        <security:intercept-url pattern="/loginService/authenticate"
            access="permitAll" />

        <security:intercept-url method="GET"
            pattern="/profileService/**" access="hasRole('user')" />

        <security:intercept-url method="PUT"
            pattern="/profileService/**" access="hasRole('admin')" />
        <security:intercept-url method="POST"
            pattern="/profileService/**" access="hasRole('admin')" />
        <security:intercept-url method="DELETE"
            pattern="/profileService/**" access="hasRole('admin')" />

    </security:http>

    <beans:bean id="unauthorizedEntryPoint"
        class="com.cheasyy.cofinding.util.UnauthorizedEntryPoint" />

    <beans:bean
        class="com.cheasyy.cofinding.util.AuthenticationTokenProcessingFilter"
        id="authenticationTokenProcessingFilter">
        <beans:constructor-arg ref="userDao" />
    </beans:bean>


</beans:beans>                          

我的web.xml是

    <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!-- Context Param -->
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/appServlet/servlet-context.xml
            /WEB-INF/spring/appServlet/security-context.xml
        </param-value>
    </context-param>

<!-- Enables Spring Security -->

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/profileService/*</url-pattern>

</filter-mapping>
<listener>
        <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
    </listener>

    <!-- This SpringCotextLoader absolutely has to come after the reasteasy 
        configuration -->
    <listener>
        <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
    </listener>

    <!-- Servlets -->
    <servlet>
        <servlet-name>Resteasy</servlet-name>
        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
    </servlet>

    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value> /WEB-INF/spring/appServlet/servlet-context.xml </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Error pages -->
    <error-page>
        <error-code>400</error-code>
        <location>/400</location>
    </error-page>

    <error-page>
        <error-code>404</error-code>
        <location>/404</location>
    </error-page>

    <error-page>
        <error-code>500</error-code>
        <location>/500</location>
    </error-page>

    <!-- ALL NEW SERVICE PATHS MUST BE SPECIFIED HERE. WHENEVER A NEW SERVICE 
        IS INTRODUCED INTO THE API IT MUST BE ADDED INTO THE RESTEASY SERVLET-MAPPING -->
    <servlet-mapping>
        <servlet-name>Resteasy</servlet-name>

        <url-pattern>/deal/*</url-pattern>
    </servlet-mapping>


    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>securedapp</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
</web-app>                                              

我的LoginLogoutServiceImpl是

    @Service
    @Path("/loginService")
    public class LoginLogoutServiceImpl extends BaseService {

        @Autowired
        private UserDetailsService userService;

        @Autowired
        @org.springframework.beans.factory.annotation.Qualifier("authenticationManager")
        private AuthenticationManager authManager;
/**
     * Authenticates a user and creates an authentication token.
     * 
     * @param username
     *            The name of the user.
     * @param password
     *            The password of the user.
     * @return A transfer containing the authentication token.
     */
    @Path("authenticate")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public TokenTransfer authenticate(@FormParam("username") String username,
            @FormParam("password") String password) {
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                username, password);
        Authentication authentication = this.authManager
                .authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);

        /*
         * Reload user as password of authentication principal will be null
         * after authorization and password is needed for token generation
         */
        UserDetails userDetails = this.userService.loadUserByUsername(username);

        return new TokenTransfer(TokenUtils.createToken(userDetails));
    }
}

当我运行应用程序时,它会出现错误,如

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.security.core.userdetails.UserDetailsService] is defined: expected single matching bean but found 2: [loginLogoutBusinessServiceImpl, userDao]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:800)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
    ... 25 more                                                                                                                                                                                                                                                                                                                                                                     

1 个答案:

答案 0 :(得分:1)

  

引起:   org.springframework.beans.factory.NoSuchBeanDefinitionException:没有   独特的豆类   [org.springframework.security.core.userdetails.UserDetailsS​​ervice]是   已定义:预期单个匹配bean但找到2:   [loginLogoutBusinessServiceImpl,userDao]

查看错误,似乎有两个bean loginLogoutBusinessServiceImpluserDao都引用了接口UserDetailsService的实现。

两个不同的类(都是spring管理的)正在实现UserDetailsService或实现它的单个类,但是使用Spring配置两个不同的bean。

因此,春天无法确定需要注射的是哪种。

@Qualifer中使用LoginLogoutServiceImpl注释告诉spring需要注入哪个注释。

例如:

@Autowired()
@Qualifier("loginLogoutBusinessServiceImpl") or @Qualifier("userDao")
private UserDetailsService userService;