我在Spring项目中配置安全性,不幸的是我遇到了问题。为什么CustomUserDetailsService.java中的自动连接userDAO为空?
以下是相关代码:
CustomUserDetailsService.java
@Service("customUserDetailsService")
@ComponentScan(basePackages="...")
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserDAO userDAO;
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// userDAO is null
UserModel user = userDAO.getUserByUsername(username);
...
}
}
弹簧security.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"
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.2.xsd">
<http pattern="/resources/**" security="none"/>
<http pattern="/login" security="none"/>
<http auto-config="true">
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<logout logout-success-url="/login?logout" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="10" />
</beans:bean>
<beans:bean id="customUserDetailsService" class="... .service.CustomUserDetailsService" />
编辑:
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
private JdbcTemplate jdbcTemplate;
public UserDAOImpl(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
public UserModel getUserByUsername(String username) {
String sql = "SELECT * FROM users WHERE username = '" + username + "'";
return jdbcTemplate.query(sql, new ResultSetExtractor<UserModel>() {
public UserModel extractData(ResultSet rs) throws SQLException, DataAccessException {
if (rs.next()) {
UserModel user = new UserModel();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("passwort"));
user.setEnabled(rs.getBoolean("enabled"));
return user;
}
return null;
}
});
}
}
以下是基于Java的配置文件中的代码段:
@Bean
public UserDAO getUserDAO() {
return new UserDAOImpl(getDataSource());
}
有趣的是,这种配置似乎有点工作。当我将UserDAO自动装入我的控制器时,它完全正常:
MainController.java
@RequestMapping(value = {"", "/", "/home"})
public String homeHandler(Model model) {
// userDAO is not null, works perfectly fine and returns the UserModel-Object as expected
UserModel user = userDAO.getUserByUsername("dx");
...
}
我已经阅读了一些Q&amp; A,但到目前为止,它涉及自定义UserDetailsService的手动实例化。我的代码出了什么问题?
答案 0 :(得分:1)
问题似乎是因为您在两个不同的地方实例化customUserDetailsService
。您在spring-security.xml文件中有<bean>
的定义,并且您在类本身上有@Service
注释。在XML
bean定义中,您没有注入UserDAO
以使其为空。
您需要简化项目以清除java配置或XML文件中的bean定义(这不是必需的,您可以使用XML + java配置,但这会使实例化哪个bean变得非常混乱)。你没有多少选择;
删除CustomUserDetailsService
的XML声明。在XML中添加<context:component-scan>
并添加包名称,并从@ComponentScan
中删除CustomUserDetailsService
。这将允许spring扫描包并注册标有@Service
,@Bean
等注释的bean。确保您的java配置类标有@Configuration
注释。
您可以决定对所有bean使用XML配置,在这种情况下,您需要删除@Bean
,@Service
等注释并在spring XML bean定义中声明所有这些注释并确保每个都注入了适当的依赖项。
您肯定需要清理bean定义,以便注入正确的依赖项。
答案 1 :(得分:0)
感谢您的回复。 Setu的回答是最有帮助的。显然,问题确实是双重实例化。我添加了<context:component-scan base-package="... .service" />
并在@Service("customUserDetailsService")
中留下了注释@ComponentScan(basePackages="...")
和CustomUserDetailsService
(没有@ComponentScan
它没有工作)。