我正在尝试将我的数据库中的用户映射到Spring Security用户,但没有太多运气。我的UserServiceImpl如下所示(当我通过servlet调用它时,自动装配通常正常工作,但在Spring Security中使用时会抛出空指针...
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService, UserDetailsService {
protected static Logger logger = Logger.getLogger("service");
@Autowired
private UserDAO userDao;
public UserServiceImpl() {
}
@Transactional
public User getById(Long id) {
return userDao.getById(id);
}
@Transactional
public User getByUsername(String username) {
return userDao.getByUsername(username);
}
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
UserDetails user = null;
try {
System.out.println(username);
User dbUser = getByUsername(username);
user = new org.springframework.security.core.userdetails.User(
dbUser.getUsername(), dbUser.getPassword(), true, true,
true, true, getAuthorities(dbUser.getAccess()));
} catch (Exception e) {
e.printStackTrace();
logger.log(Level.FINE, "Error in retrieving user");
throw new UsernameNotFoundException("Error in retrieving user");
}
// Return user to Spring for processing.
// Take note we're not the one evaluating whether this user is
// authenticated or valid
// We just merely retrieve a user that matches the specified username
return user;
}
public Collection<GrantedAuthority> getAuthorities(Integer access) {
// Create a list of grants for this user
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
// All users are granted with ROLE_USER access
// Therefore this user gets a ROLE_USER by default
logger.log(Level.INFO, "User role selected");
authList.add(new GrantedAuthorityImpl("ROLE_USER"));
// Check if this user has admin access
// We interpret Integer(1) as an admin user
if (access.compareTo(1) == 0) {
// User has admin access
logger.log(Level.INFO, "Admin role selected");
authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
}
// Return list of granted authorities
return authList;
}
}
我得到以下异常(第一行是System.out)
dusername
java.lang.NullPointerException
at org.assessme.com.service.UserServiceImpl.getByUsername(UserServiceImpl.java:40)
at org.assessme.com.service.UserServiceImpl.loadUserByUsername(UserServiceImpl.java:50)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:81)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:194)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:722)
所以看起来我的userDao没有正确自动装配,但是当我从servlet调用服务层时它工作正常,显然不是在使用Spring-Security时。
第40行指的是返回userDao.getByUsername(用户名);
有没有人有任何想法如何让userDao通过@autowired填充?正如我所说的,当我通过servlet调用它时它工作正常,而不是在尝试使用spring-security时。
有没有更简单的方法可以在Spring-security中映射用户和密码?
我的security-app-context如下......
<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"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx">
<context:annotation-config />
<context:component-scan base-package="org.assessme.com." />
<http pattern="/static/**" security="none" />
<http use-expressions="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/*" access="isAuthenticated()" />
<!-- <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"
/> -->
<!-- <intercept-url pattern="/listAccounts.html" access="isAuthenticated()"
/> -->
<!-- <intercept-url pattern="/post.html" access="hasAnyRole('supervisor','teller')"
/> -->
<!-- <intercept-url pattern="/*" access="denyAll" /> -->
<form-login />
<logout invalidate-session="true" logout-success-url="/"
logout-url="/logout" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="UserDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<context:component-scan base-package="org.assessme.com" /><context:annotation-config />
<beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService" autowire="byType"/>
</beans:beans>
我想我的问题是,为什么我的userDao @Autowired不使用spring-security,但是当在servlet中使用它来返回用户对象时它可以正常工作?例如,以下servlet工作正常......
为什么我的自动装配(因为它抛出一个NPE)在弹出安全性时没有工作,但是从servlet调用它时工作正常?
编辑: - 补充说但现在我得到了
ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 9 in XML document from ServletContext resource [/WEB-INF/spring/security-app-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 30; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'context:annotation-config'.
答案 0 :(得分:8)
您关心通过bean声明创建服务:
<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService"/>
因此,您需要通过设置属性autowire
将其配置为符合自动装配条件。默认值为No
。配置如下:
<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService" autowire="byType" />
另外,您可以通过配置属性autowire-candidate =“true”来指示此bean将参与其他bean autowire进程。
检查documentation以找出哪个是bean的最佳策略是自动装配其属性。我个人使用byType
和constructor
,但这实际上取决于您的要求。
另一种解决方案是在您的上下文的标记default-autowire="true"
中配置beans
。
答案 1 :(得分:2)
我认为您在春季安全环境中错过了<context:annotation-config/>
和<context:component-scan base-package="..."/>
。
答案 2 :(得分:0)
我只是注意到你的xml文件中的标记加倍了。
<context:component-scan base-package="org.assessme.com" /><context:annotation-config />
让我们尝试删除它。
答案 3 :(得分:0)
您所要做的就是用以下内容替换您的安全应用程序上下文:
<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"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx">
<context:annotation-config>
<context:component-scan base-package="org.assessme.com." />
<http pattern="/static/**" security="none" />
<http use-expressions="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/*" access="isAuthenticated()" />
<!-- <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"
/> -->
<!-- <intercept-url pattern="/listAccounts.html" access="isAuthenticated()"
/> -->
<!-- <intercept-url pattern="/post.html" access="hasAnyRole('supervisor','teller')"
/> -->
<!-- <intercept-url pattern="/*" access="denyAll" /> -->
<form-login />
<logout invalidate-session="true" logout-success-url="/"
logout-url="/logout" />
</http>
<authentication-manager>
<authentication-provider user-service-ref="UserDetailsService">
<password-encoder ref="passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<context:annotation-config />
你错过了打字的部分,我为你纠正了。