2011-05-07 2 views
16

저는 Spring 3 및 Spring Security를 ​​사용하는 프로젝트에서 작업하고 있습니다. 내 문제는 IoC 컨테이너입니다. Spring Security-3에 대한 UserDetailsService의 구현을 직접 작성했을 때 문제가 시작되었습니다. 나는 다른 질문들을 점검했지만 여전히 문제를 해결할 수 없었다. 문제의@Autowired 객체는 한 클래스에서 null 값을 얻고 다른 클래스는 성공적으로 연결됩니다.

정의는 다음과 같습니다

나는 두 개의 별도의 클래스를 (하나는 @Controller를 확장 UsersController.java@Service를 확장 ProjectUserDetailsService입니다) 즉를 자동 설정할 수있는 공통의 객체를 사용합니다. 그러나 객체가 UsersController에서 성공적으로 자동 실행되는 동안이 클래스의 객체 (ProjectUserDetailsService)가 성공적으로 만들어졌지만 (디버깅으로 확인했습니다) nullProjectUserDetailsService 클래스에 있습니다.

제안 사항 해결 방법?

여기에 내 web.xml, project-servlet.xmlproject-security.xml 개의 파일과 관련 클래스가 있습니다.

Web.xml`

<?xml version="1.0" encoding="UTF-8"?> 
<!-- 
    - Tutorial web application 
    - 
    --> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> 
    <display-name>Ecognitio with Spring Security</display-name> 
    <context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
      /WEB-INF/ecognitio-servlet.xml 
      /WEB-INF/ecognitio-security.xml 
     </param-value> 
    </context-param> 
    <context-param> 
    <param-name>webAppRootKey</param-name> 
    <param-value>tutorial.root</param-value> 
    </context-param> 
    <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>/*</url-pattern> 
    </filter-mapping> 
    <listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
    </listener> 
    <listener> 
    <listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class> 
    </listener> 
    <servlet> 
    <servlet-name>ecognitio</servlet-name> 
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    <load-on-startup>1</load-on-startup> 
    </servlet> 
    <servlet-mapping> 
    <servlet-name>project</servlet-name> 
    <url-pattern>*.action</url-pattern> 
    </servlet-mapping> 
    <servlet-mapping> 
    <servlet-name>project</servlet-name> 
    <url-pattern>*.html</url-pattern> 
    </servlet-mapping> 
    <welcome-file-list> 
    <welcome-file>index.jsp</welcome-file> 
    </welcome-file-list> 
</web-app> 

project-servlet.xml

<?xml version="1.0" encoding="UTF-8"?> 

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

    <!-- Scans the classpath of this application for @Components to deploy as beans --> 
    <context:component-scan base-package="com.project" /> 

    <!-- Configures the @Controller programming model --> 
    <mvc:annotation-driven /> 

    <bean id="messageSource" 
      class="org.springframework.context.support.ResourceBundleMessageSource" 
      p:basename="Messages"/> 

    <!-- misc --> 
<!-- <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 
     <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 
     <property name="suffix" value=".jsp"/> 
    </bean> --> 


    <bean id="viewResolver" 
     class="org.springframework.web.servlet.view.UrlBasedViewResolver"> 

     <property name="viewClass"> 
     <value> 
       org.springframework.web.servlet.view.tiles2.TilesView 
      </value> 
     </property> 
    </bean> 

    <bean id="tilesConfigurer" 
    class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"> 
     <property name="definitions"> 
      <list> 
       <value>/WEB-INF/tiles.xml</value> 
      </list> 
     </property> 
    </bean> 

    <!-- Configures Hibernate - Database Config --> 
    <import resource="db-config.xml" /> 
</beans> 

project-security.xml

<?xml version="1.0" encoding="UTF-8"?> 

<!-- 
    - Sample namespace-based configuration 
    - 
    --> 

<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" 
    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"> 

    <debug /> 

    <global-method-security pre-post-annotations="enabled"> 
     <!-- AspectJ pointcut expression that locates our "post" method and applies security that way 
     <protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/> 
     --> 
    </global-method-security> 

    <http pattern="/loggedout.jsp" security="none"/> 

    <http use-expressions="true" > 
     <intercept-url pattern="/secure/extreme/**" access="hasRole('ROLE_SUPERVISOR')"/> 
     <intercept-url pattern="/secure/**" access="isAuthenticated()" /> 

     <!-- 
      Allow all other requests. In a real application you should 
      adopt a whitelisting approach where access is not allowed by default 
      --> 
     <intercept-url pattern="/login.jsp*" access="isAuthenticated()==false"/> 
     <intercept-url pattern="/timeout.jsp*" access="isAuthenticated()==false"/> 
     <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 

     <!-- <intercept-url pattern="/**" access="permitAll" /> --> 
     <form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" default-target-url="/dashboard.html" /> 
     <logout logout-success-url="/login.jsp" delete-cookies="JSESSIONID"/> 
     <remember-me /> 
<!-- 
    Uncomment to enable X509 client authentication support 
     <x509 /> 
--> 
     <!-- Uncomment to limit the number of sessions a user can have 
     <session-management invalid-session-url="/login.jsp"> 
      <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> 
     </session-management> 
     --> 

    </http> 

      <!-- HERE IS WHERE I USE an object of ProjectUserDetailsService --> 
    <authentication-manager> 
     <authentication-provider user-service-ref="userDetailsService" /> 
    </authentication-manager> 


<!-- 

</beans:beans> 

UsersController.java

01,235,164 (UsersDAO 클래스의 객체를 autowiring이 클래스 성공)
package com.project.users; 

//required imports 



@Controller 
public class UsersControllers 
{ 

@Autowired 
private UsersDAO usersDAO; 

    //Some more autowires and some class specific code 


} 

ProjectUserDetailsService.java 두 번째 빈은 project-servlet.xml에 규정 된 지정 콩 주석 패키지 구성 요소 스캔하지 않기 때문에

package com.project.security; 

import java.util.ArrayList; 
import java.util.Collection; 

//required imports 


@SuppressWarnings("deprecation") 
@Service("userDetailsService") 
public class ProjectUserDetailsService implements UserDetailsService { 

    @Autowired 
    private UsersDAO usersDAO; 
    @Autowired private Assembler assembler; 

    @Transactional(readOnly = true) 
    public UserDetails loadUserByUsername(String username) 
     throws UsernameNotFoundException, DataAccessException { 

    UserDetails userDetails = null; 
    //For debugging purposes 
    if(usersDAO==null){ 
     System.out.println("DAO IS NULL"); 
     System.out.println("DAO IS NULL"); 
     System.out.println("DAO IS NULL"); 

    } 
    User userEntity = usersDAO.findUserbyEmail("'"+username+"'"); 


    if (userEntity == null) 
     throw new UsernameNotFoundException("user not found"); 

    return assembler.buildUserFromUserEntity(userEntity); 

    } 
} 
+1

'project-security.xml'에서'ProjectUserDetailsService'에 대한 언급이 전혀 없습니다. 실종 됐나요? – skaffman

+0

ProjectUserDetailsService.java가 @Service ("userDetailsService")로 정의되었으므로 부트 스트랩에이 이름의 bean이 작성됩니다. 그래서 이것은 문제가 아닙니다. –

답변

1

을 (UsersDAO의에서 autowiring이 작동하지 않는 경우) : 그것은하지

<context:component-scan base-package="com.project" /> 

서비스로 간주하지 않고 주석을 번역하지 않습니다.

당신은 그것을 더 확장하거나 com.project으로 또는 다른 사람과 같이 시작하는 패키지로 이동해야합니다

<context:component-scan base-package="com" /> 
+0

미안하지만 잘못 입력했습니다. ProjectUserDetailsService.java는 실제로 com.project 패키지에 있습니다. 그래서 이것은 문제가 아닙니다. projectUserDetailsService의 userDetailsService라는 이름의 bean이 작성되었지만 그 종속성은 자동으로 작성되지 않았습니다. 나는 그 문제를 바로 잡았다. –

4

가 네,이 봄 보안 버그가 있다면. 내가 모르는 봄 보안 클래스로부터 상속 콩에 물체를 autowire하기 불가능한 것으로 보인다하거나 있다면 보안을 위해 또는 무엇을합니다. 누군가 explana를 가지고 있다면 나는 그것을 듣고 싶어한다. xml 구성 (@Autowired 주석을 사용하지 않고)을 통해 수동으로 빈을 주입함으로써 문제를 해결할 수 있습니다. 한마디로주의 할 점은 ..

나는이 작업을 수행했으며 주석을 사용하는 userDao (특히 @Transactional)가 더 이상 트랜잭션에서 작동하지 않는다는 사실을 발견했습니다.내 userDao가 여러 곳에서 사용되고있었습니다. 그래도 내 사용자 지정 AbstractUserDetailsAuthenticationProvider에 삽입하면 더 이상 사용 된 다른 클래스의 트랜잭션에서 작동하지 않습니다. 사용자 정의 AbstractUserDetailsAuthenticationProvider에 대한 주입을 제거하면 @Autowired 또는 manual xml injection을 통해받은 다른 객체가 사용할 때 트랜잭션 기능이 내 userDao로 복원되었습니다.

그래서 내 userDao를 Spring Security 컨텍스트로 가져오고 @Transactional로 유지 했습니까?

public class UserDaoFactory { 

private static UserDao userDao; 

public static UserDao getUserDao() { 
    return UserDaoFactory.userDao; 
} 

public void setUserDao(UserDao userDao) { 
    UserDaoFactory.userDao = userDao; 
} 
} 

그런 다음 스프링 컨테이너에이 당신의 DAO 두 개체를 넣어 :

<bean id="userDao" class="com.package.UserDaoImpl"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="userDaoFactory" class="com.package.UserDaoFactory"> 
    <property name="userDao" ref="userDao" /> 
</bean> 

는 그래서 userDao이 userDaoFactory에 autowire가 얻을 것이다 나는 공장 클래스를 생성했다. 그것 모두는 @Transactional 기능을 가지고있을 것이다 (스프링 보안이 그것을 제거하지 않았기 때문에?). 그런 다음 봄 보안 목적에 당신은 할 수 있습니다 :
userDao = UserDaoFactory.getUserDao(); 

나는 초기화하는 동안 한 번 이상 작업을 수행하는 객체 AbstractUserDetailsAuthenticationProvider 내 사용자 지정에 ServletContextAware을 구현하고, 비올라.

@Autowired 문제를 극복하기 위해 xml 구성을 통해 bean을 스프링 보안 객체에 수동으로 주입 할 수 있지만, @Transactional에서 DAO를 래핑하려는 경우 새로운 문제가 발생할 수 있습니다.

이제 어쩌면 누군가 이런 일이 일어날 수도 있습니다. 그것은 내 구성 부분에서 잘못 구성 될 수 있습니다 (저는 봄 전문가가 아니란 것을 인정합니다), 또는 봄의 기능 일 수 있습니다. 나는 누군가가 말하고 무엇을 개선해야하는지 듣고 싶습니다.

0

이는 AutowiredAnnotationBeanPostProcessor과 같은 BeanPostProcessors를 사용하고 <debug /> 요소를 사용할 때 문제가되는 SEC-1911이 원인 일 수 있습니다. <debug />을 제거하고 @Autowired가 다시 작동하는지 확인해보십시오. 이 첫 번째 문제는 SEC-1885의 복제본입니다.이 부분은 수정되었지만 첫 번째 문제의 증상이이 문제와 더 잘 일치합니다.

-1

나는 동일한 문제가있었습니다. 이것은 여러 가지 방법으로 발생할 수 있지만, 제 경우에는 autowired을 사용하는 대신 새로운 객체를 작성했습니다. 즉 :

private Service service = new ServiceImpl(); 

는 대신 :

@Autowired private Service service; 

이 저장소 주입을 사용하여 서비스에 아니었지만, 그 꼭대기에 컨트롤러이다.

관련 문제