本文的目的是介绍Spring-security中UserDetails上的@Autowired返回异常的详细情况,特别关注springsecurity返回错误信息的相关信息。我们将通过专业的研究、有关
本文的目的是介绍Spring-security中UserDetails上的@Autowired返回异常的详细情况,特别关注springsecurity返回错误信息的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解Spring-security中UserDetails上的@Autowired返回异常的机会,同时也不会遗漏关于java – Spring Security:未调用自定义UserDetailsService(使用Auth0身份验证)、java – 无法自动连线字段:private org.springframework.security.core.userdetails.UserDetailsService、java-Spring Security 3.1并返回匿名UserDetails、java-Spring Security如何在不登录的情况下更新userDetails的知识。
本文目录一览:- Spring-security中UserDetails上的@Autowired返回异常(springsecurity返回错误信息)
- java – Spring Security:未调用自定义UserDetailsService(使用Auth0身份验证)
- java – 无法自动连线字段:private org.springframework.security.core.userdetails.UserDetailsService
- java-Spring Security 3.1并返回匿名UserDetails
- java-Spring Security如何在不登录的情况下更新userDetails
Spring-security中UserDetails上的@Autowired返回异常(springsecurity返回错误信息)
请告诉我哪里有问题?这是我的项目:https :
//github.com/intrade/inventory
我尝试使用java
config启用Spring安全性,并且当我尝试将类型的依赖项MyCustomUserDetailsService
注入我的SecurityConfig
类时,我得到一个异常:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''securityConfig'': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.springapp.mvc.services.MyCustomUserDetailsService com.springapp.mvc.InitApp.SecurityConfig.myCustomUserDetailsService; nested exception is java.lang.IllegalArgumentException: Can not set com.springapp.mvc.services.MyCustomUserDetailsService field com.springapp.mvc.InitApp.SecurityConfig.myCustomUserDetailsService to com.sun.proxy.$Proxy38 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:607) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:383) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4887) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5381) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633) at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1551) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322) at sun.rmi.transport.Transport$1.run(Transport.java:177) at sun.rmi.transport.Transport$1.run(Transport.java:174) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:173) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744)Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.springapp.mvc.services.MyCustomUserDetailsService com.springapp.mvc.InitApp.SecurityConfig.myCustomUserDetailsService; nested exception is java.lang.IllegalArgumentException: Can not set com.springapp.mvc.services.MyCustomUserDetailsService field com.springapp.mvc.InitApp.SecurityConfig.myCustomUserDetailsService to com.sun.proxy.$Proxy38 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285) ... 56 moreCaused by: java.lang.IllegalArgumentException: Can not set com.springapp.mvc.services.MyCustomUserDetailsService field com.springapp.mvc.InitApp.SecurityConfig.myCustomUserDetailsService to com.sun.proxy.$Proxy38 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) at java.lang.reflect.Field.set(Field.java:741) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:510) ... 58 moreJan 24, 2014 1:18:32 PM org.apache.catalina.core.ApplicationContext log
先感谢您!
答案1
小编典典您正在尝试按类自动连接您的用户详细信息服务,但这是行不通的,因为spring
bean实际上是围绕该类创建的代理(而不是该类的实例)。但是,代理将实现原始bean的所有接口,因此按接口进行注入是安全的。
交换此行:
@Autowiredprivate MyCustomUserDetailsService myCustomUserDetailsService;
为此:
@Autowiredprivate UserDetailsService myCustomUserDetailsService;
阅读Spring AOP中有关 代理机制 的部分,以了解详细信息。
java – Spring Security:未调用自定义UserDetailsService(使用Auth0身份验证)
我正在使用Auth0来保护我的API,这非常有效.我的设置& config与Auth0文档中的suggested setup相同:
// SecurityConfig.java @Configuration @EnableWebSecurity(debug = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { // auth0 config vars here @Override protected void configure(HttpSecurity http) { JwtWebSecurityConfigurer .forRS256(apiAudience,issuer) .configure(http) .authorizeRequests() .antMatchers(HttpMethod.GET,"/api/public").permitAll() .antMatchers(HttpMethod.GET,"/api/private").authenticated(); } }
使用此设置,spring安全主体从jwt标记设置为userId(sub):auth0 | 5b2b ….但是,我希望它设置为匹配用户(来自我的数据库)而不仅仅是userId .我的问题是如何做到这一点.
我试过的
我已经尝试实现从this tutorial复制的自定义数据库支持的UserDetailsService.
然而,无论我如何尝试将其添加到我的conf中,它都不会被调用.我尝试过几种不同的方式添加它没有效果:
// SecurityConfig.java (changes only) // My custom userDetailsService,overriding the loadUserByUsername // method from Spring Framework's UserDetailsService. @Autowired private MyUserDetailsService userDetailsService; protected void configure(HttpSecurity http) { http.userDetailsService(userDetailsService); // Option 1 http.authenticationProvider(authenticationProvider()); // Option 2 JwtWebSecurityConfigurer [...] // The rest unchanged from above } @Override // Option 3 & 4: Override the following method protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(authenticationProvider()); // Option 3 auth.userDetailsService(userDetailsService); // Option 4 } @Bean // Needed for Options 2 or 4 public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); return authProvider; }
不幸的是,由于我需要将其与Auth0身份验证相结合,所以没有类似的“userDetails not called called”问题帮助了我.
我并不认为我正走在正确的道路上.我觉得很奇怪,在这个极为常见的用例中我找不到Auth0的任何文档,所以也许我错过了一些明显的东西.
PS:不确定是否相关,但在init期间始终记录以下内容.
Jun 27,2018 11:25:22 AM com.test.UserRepository initDao INFO: No authentication manager set. Reauthentication of users when changing passwords will not be performed.
编辑1:
根据Ashish451的回答,我尝试复制他的CustomUserDetailsService,并将以下内容添加到我的SecurityConfig中:
@Autowired private CustomUserDetailsService userService; @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Autowired public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception { auth.userDetailsService( userService ); }
不幸的是,通过这些更改,仍未调用CustomUserDetailsService.
编辑2:
添加@norberto Ritzmann建议的日志记录方法时的输出:
Jul 04,2018 3:49:22 PM com.test.repositories.UserRepositoryImpl initDao INFO: No authentication manager set. Reauthentication of users when changing passwords will not be performed. Jul 04,2018 3:49:22 PM com.test.runner.JettyRunner testUserDetailsImpl INFO: UserDetailsService implementation: com.test.services.CustomUserDetailsService
解决方法
我不知道什么是apiAudience,发行人,但它产生了JWT的子猜测.
您的问题是您希望根据数据库更改JWT子.
我最近在Spring Boot Application中实现了JWT安全性.
我从数据库中获取UserName之后设置它.
为清楚起见,我添加了带pkg信息的代码.
//我的适配器类和你的一样,除了我添加过滤器的一件事.在此过滤器中,我正在验证JWT令牌.每次触发安全休息URL时都会调用此过滤器.
import java.nio.charset.StandardCharsets; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.thymeleaf.Spring5.SpringTemplateEngine; import org.thymeleaf.Spring5.templateresolver.SpringResourceTemplateResolver; import com.dev.myapp.jwt.model.CustomUserDetailsService; import com.dev.myapp.security.RestAuthenticationEntryPoint; import com.dev.myapp.security.TokenAuthenticationFilter; import com.dev.myapp.security.TokenHelper; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Autowired private CustomUserDetailsService jwtUserDetailsService; // Get UserDetail bu UserName @Autowired private RestAuthenticationEntryPoint restAuthenticationEntryPoint; // Handle any exception during Authentication @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } // Binds User service for User and Password Query from Database with Password Encryption @Autowired public void configureGlobal( AuthenticationManagerBuilder auth ) throws Exception { auth.userDetailsService( jwtUserDetailsService ) .passwordEncoder( passwordEncoder() ); } @Autowired TokenHelper tokenHelper; // Contains method for JWT key Generation,Validation and many more... @Override protected void configure(HttpSecurity http) throws Exception { http .sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS ).and() .exceptionHandling().authenticationEntryPoint( restAuthenticationEntryPoint ).and() .authorizeRequests() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated().and() .addFilterBefore(new TokenAuthenticationFilter(tokenHelper,jwtUserDetailsService),BasicAuthenticationFilter.class); http.csrf().disable(); } // Patterns to ignore from JWT security check @Override public void configure(WebSecurity web) throws Exception { // TokenAuthenticationFilter will ignore below paths web.ignoring().antMatchers( HttpMethod.POST,"/auth/login" ); web.ignoring().antMatchers( HttpMethod.GET,"/","/assets/**","/*.html","/favicon.ico","/**/*.html","/**/*.css","/**/*.js" ); } }
//用户服务获取用户详细信息
@Transactional @Repository public class CustomUserDetailsService implements UserDetailsService { protected final Log LOGGER = LogFactory.getLog(getClass()); @Autowired private UserRepo userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User uu = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException(String.format("No user found with username '%s'.",username)); } else { return user; } } }
//未经授权的访问处理程序
@Component public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request,HttpServletResponse response,AuthenticationException authException) throws IOException { // This is invoked when user tries to access a secured REST resource without supplying any credentials response.sendError(HttpServletResponse.SC_UNAUTHORIZED,authException.getMessage()); } }
//用于验证JWT令牌的过滤链
import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.servletexception; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.filter.OncePerRequestFilter; public class TokenAuthenticationFilter extends OncePerRequestFilter { protected final Log logger = LogFactory.getLog(getClass()); private TokenHelper tokenHelper; private UserDetailsService userDetailsService; public TokenAuthenticationFilter(TokenHelper tokenHelper,UserDetailsService userDetailsService) { this.tokenHelper = tokenHelper; this.userDetailsService = userDetailsService; } @Override public void doFilterInternal( HttpServletRequest request,FilterChain chain ) throws IOException,servletexception { String username; String authToken = tokenHelper.getToken(request); logger.info("AuthToken: "+authToken); if (authToken != null) { // get username from token username = tokenHelper.getUsernameFromToken(authToken); logger.info("UserName: "+username); if (username != null) { // get user UserDetails userDetails = userDetailsService.loadUserByUsername(username); if (tokenHelper.validatetoken(authToken,userDetails)) { // create authentication TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails); authentication.setToken(authToken); SecurityContextHolder.getContext().setAuthentication(authentication); // Adding Token in Security COntext } }else{ logger.error("Something is wrong with Token."); } } chain.doFilter(request,response); } }
// TokenBasedAuthentication类
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.userdetails.UserDetails; public class TokenBasedAuthentication extends AbstractAuthenticationToken { private static final long serialVersionUID = -8448265604081678951L; private String token; private final UserDetails principle; public TokenBasedAuthentication( UserDetails principle ) { super( principle.getAuthorities() ); this.principle = principle; } public String getToken() { return token; } public void setToken( String token ) { this.token = token; } @Override public boolean isAuthenticated() { return true; } @Override public Object getCredentials() { return token; } @Override public UserDetails getPrincipal() { return principle; } }
// JWT生成和验证逻辑的助手类
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import com.dev.myapp.common.TimeProvider; import com.dev.myapp.entity.User; @Component public class TokenHelper { protected final Log LOGGER = LogFactory.getLog(getClass()); @Value("${app.name}") // reading details from property file added in Class path private String APP_NAME; @Value("${jwt.secret}") public String SECRET; @Value("${jwt.licenseSecret}") public String LICENSE_SECRET; @Value("${jwt.expires_in}") private int EXPIRES_IN; @Value("${jwt.mobile_expires_in}") private int MOBILE_EXPIRES_IN; @Value("${jwt.header}") private String AUTH_HEADER; @Autowired TimeProvider timeProvider; // return current time. Basically Deployment time. private SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS512; // Generate Token based on UserName. You can Customize this public String generatetoken(String username) { String audience = generateAudience(); return Jwts.builder() .setIssuer( APP_NAME ) .setSubject(username) .setAudience(audience) .setIssuedAt(timeProvider.Now()) .setExpiration(generateExpirationDate()) .signWith( SIGNATURE_ALGORITHM,SECRET ) .compact(); } public Boolean validatetoken(String token,UserDetails userDetails) { User user = (User) userDetails; final String username = getUsernameFromToken(token); final Date created = getIssuedAtDateFromToken(token); return ( username != null && username.equals(userDetails.getUsername()) ); } // If Token is valid will extract all claim else throw appropriate error private Claims getAllClaimsFromToken(String token) { Claims claims; try { claims = Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token) .getBody(); } catch (Exception e) { LOGGER.error("Could not get all claims Token from passed token"); claims = null; } return claims; } private Date generateExpirationDate() { long expiresIn = EXPIRES_IN; return new Date(timeProvider.Now().getTime() + expiresIn * 1000); } }
对于这个日志
No authentication manager set. Reauthentication of users when changing passwords
由于尚未使用Name loadUserByUsername实现方法.你得到这个日志.
编辑1:
我正在使用Filter Chain来验证令牌并在安全上下文中添加用户,这将从令牌中提取….
使用JWT并且您使用的是AuthO,只有实现不同.我为完整的工作流程添加了完整的实施.
您专注于从WebSecurityConfig类实现authenticationManagerBean和configureGlobal以使用UserService.
和TokenBasedAuthentication类实现.
其他你可以跳过的东西.
java – 无法自动连线字段:private org.springframework.security.core.userdetails.UserDetailsService
每次运行我的应用程序,我得到:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘securityConfig’: Injection of autowired dependencies Failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation; nested exception is org.springframework.beans.factory.NoSuchBeanDeFinitionException: No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
我已经通过一个精细的梳子我的代码,无法确定的问题.
Spring Framework版本:3.2.5.RELEASE
Spring Security版本:3.2.0.M2
SecurityConfig.java
package com.entirety.app.config; import com.entirety.app.service.implement.UserDetailsServiceImplementation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import javax.sql.DataSource; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; @Autowired private UserDetailsService userDetailsServiceImplementation; @Override protected void registerauthentication(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource); } @Override protected void configure(HttpSecurity http) throws Exception { http.userDetailsService(userDetailsServiceImplementation) .authorizeUrls() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/sec/**").hasRole("MODERATOR") .antMatchers("/*").permitAll() .anyRequest().anonymous().and().exceptionHandling().accessDeniedPage("/denied").and() .formLogin() .loginProcessingUrl("/j_spring_security_check") .loginPage("/login") .failureUrl("/error-login") .and() .logout() .logoutUrl("/j_spring_security_logout") .logoutSuccessUrl("/"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
CrmUserService.java
@Service("userService") @Transactional public class CrmUserService implements UserDetailsService { @Autowired private UserDAO userDAO; @Override public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException { com.entirety.app.domain.User domainUser = userDAO.getUser(login); boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; return new User( domainUser.getLogin(),domainUser.getpassword(),enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,getAuthorities(domainUser.getAuthority().getId()) ); } public Collection<? extends GrantedAuthority> getAuthorities(Integer role) { List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role)); return authList; } public List<String> getRoles(Integer role) { List<String> roles = new ArrayList<String>(); if (role.intValue() == 1) { roles.add("ROLE_MODERATOR"); roles.add("ROLE_ADMIN"); } else if (role.intValue() == 2) { roles.add("ROLE_MODERATOR"); } return roles; } public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } }
没有什么逻辑的理由,为什么它应该是失败,但它是.
注意:
我的IDE可以链接自动连接(这是它知道它的自动连接和所有内容),但编译失败.
编辑2:
我已经从SecurityConfig.java文件中删除了以下代码
@Autowired private UserDataService userDataService;
并将其添加到我知道的POJO和控制器之一,并定期调用并包含其他服务.
在这种情况下,将该代码粘贴到我的baseController.java文件中,该文件指向呈现主页.
该服务正确编译,甚至可以在控制器内调用.
所以这个问题仅仅是配置文件,例如SecurityConfig.java,这是唯一的时候它不起作用.
编辑3:添加额外的文件
SecurityInitializer.java
@Order(2) public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { }
WebInitializer.java
@Order(1) public class WebAppInitializer extends AbstractAnnotationConfigdispatcherServletinitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { PersistanceConfig.class,SecurityConfig.class }; //To change body of implemented methods use File | Settings | File Templates. } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] {"/"}; } // @Override // protected Filter[] getServletFilters() { // CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); // characterEncodingFilter.setEncoding("UTF-8"); // return new Filter[] { characterEncodingFilter}; // } }
MVC-调度-servlet.xml中
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.entirety.app"/> <bean> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml中
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring MVC Application</display-name> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
解决方法
看来你有多个问题.
web.xml与AbstractAnnotationConfigdispatcherServletinitializer
您创建的应用程序具有配置名为mvc-dispatcher的dispatcherServlet的web.xml. mvc-dispatcher具有mvc-dispatcher-servlet.xml的配置,它加载了com.springapp.sectest包中的所有bean.这意味着mvc-dispatcher可以找到您的UserDetailsService.
该应用程序还有一个AbstractAnnotationConfigdispatcherServletinitializer,它创建了一个dispatcherServlet,它加载了WebConfig java配置.此dispatcherServlet无法看到由mvc-dispatcher创建的任何Bean.
简而言之,您应该使用web.xml或AbstractAnnotationConfigdispatcherServletinitializer配置dispatcherServlet,而不是同时配置dispatcherServlet.
getRootConfigClasses与getServletConfigClasses
getRootConfigClasses中的任何配置通常称为根配置或父配置,并且无法查看getServletConfigClasses中定义的bean. Spring Security使用由@EnableWebSecurity注释创建的名为springSecurityFilterChain的Filter来保护您在getRootConfigClasses中定义的应用程序.这意味着通常最好将Spring Security的配置放在getRootConfigClasses中.有一些例外,就像您想要在Spring MVC控制器上执行方法安全性.
getServletConfigClasses中的任何配置通常称为子配置,并且可以查看在getRootConfigClasses中定义的bean. getServletConfigClasses配置dispatcherServlet,并且必须包含Spring MVC(即控制器,ViewResovlers等)的bean.在getRootConfigClasses中定义的任何Spring MVC bean可见但不被使用.
此设置虽然有点混乱,但您可以使用具有隔离配置的多个dispatcherServlet实例.实际上,很少有多个dispatcherServlet实例.
鉴于上述信息,您应将UserDetailsService声明及其所有依赖bean移动到getRootConfigClasses.这将确保SecurityConfig.java可以找到UserDetailsService.
拉请求修复
我已经提交了一个公关,以获得您的应用程序,使其从没有错误https://github.com/worldcombined/AnnotateFailed/pull/1开始.几个笔记
>测试不使用父和子上下文,因此它不反映运行应用程序
>我不得不移动资源文件夹,以便被正确地拾起
>我没有这样做,所以你实际上可以认证.没有login.jsp,你提供的UserDetailsService总是返回null而不是我试图证明这里的错误被回答了.
原始答案
基于此评论:
@ComponentScan is undertaken in my mvc-dispatcher-servlet.xml as
<context:component-scan base-package=”com.entirety.app”/>
看来您正在配置dispatcher配置中的服务,而不是在根上下文中.
Spring Security的配置通常在根上下文中配置.例如,可以扩展AbstractSecurityWebApplicationInitializer,如下所示:
import org.springframework.security.web.context.*; public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { }
您如何导入安全配置?如果Spring Security配置在根上下文中,那么它将不会看到在dispatcher Servlet上下文中定义的bean.
解决方案是在根上下文中移动服务配置,或将Spring Security配置移动到调度程序的ApplicationContext.例如,如果调度程序servlet命名为mvc,则将Spring Security配置移动到调度程序上下文将如下所示.
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { protected String getdispatcherWebApplicationContextSuffix() { return "mvc"; } }
java-Spring Security 3.1并返回匿名UserDetails
我试图找出如何让Spring Security为该调用返回匿名用户的UserDetails对象:
SecurityContextHolder.getContext().getAuthentication().getPrincipal()
我知道没有特殊配置,该调用将返回一个字符串,而不是您使用自定义UserDetailsService实现创建的UserDetails对象,但是我宁愿不时在各处检查“ if(principal instanceof String)”.有没有办法用Spring配置来做到这一点-一种将匿名UserDetails对象存储在用户的会话上下文中直到他们登录的方法?从表面上看,我想为每个访客提供一个唯一的匿名UserDetails,以便我可以跟踪它的个人使用情况.
我还注意到,使用“ PreAuthorize”注释保护的方法似乎不支持匿名用户进行hasRole检查.我确定这是我做错任何事情的症状.这是一个例子:
@RequestMapping(value = "/almanac/new",method = RequestMethod.GET)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public String newSetup(ModelMap model) {
这是我的spring安全上下文(除了封闭的bean节点之外,其余都是完整的).您可以注意到,我尝试启用“匿名”
<debug />
<http pattern="/js/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/images/**" security="none" />
<http pattern="/loggedout.jsp" security="none"/>
<http name="httpSiteMap" use-expressions="true">
<custom-filter ref="almanacUsrPwdAuthProcFilter" before="FORM_LOGIN_FILTER"/>
<intercept-url pattern="/login*" access="isAnonymous()" />
<intercept-url pattern="/home/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/**" access="isAnonymous()" />
<form-login login-page="/login.jsp"
default-target-url="/home.htm"
always-use-default-target="false" />
<logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
<session-management invalid-session-url="/timeout.jsp">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
<anonymous enabled="true" />
</http>
<global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />
<authentication-manager alias="mainAuthMgr">
<authentication-provider ref="almanacAuthenticationProvider"/>
</authentication-manager>
基于您在此处看到的代码的任何其他建议都将受到欢迎.
无论如何,如果您需要更详细的访问安全性上下文,最好使用自定义接口将应用程序代码与Spring Security类分离(请参见my answer on using a security context accessor).这样,您应该只在一个地方检查主体的类型,而不是在要访问用户数据的“各处”重复检查.
如果您绝对希望身份验证对象中始终具有相同的主体类型,而不管用户是否匿名,那么您将必须通过命名空间禁用匿名身份验证,并基于现有的AnonymousAuthenticationFilter添加自定义过滤器来执行此工作.
java-Spring Security如何在不登录的情况下更新userDetails
我是Spring Security的新手.
我已经实现了UserDetails来创建自己的用户.我也有自定义的userDetailsService.现在一切正常,但是我需要在不登录的情况下更新有关用户的信息.如何做到这一点?如何从上下文中接收信息然后进行更改?
提前致谢
只需使用UserDetailsService加载用户(UDS毕竟只是DAO),然后根据需要进行修改和保存.这将非常有用,例如在管理用例中(例如,管理员纠正了用户名中的拼写错误).
让我知道这是否不是您要的.
编辑:
好的,响应您的评论(我是从内存中这样做的,所以可能不是100%):
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
CustomUser user = (CustomUser) auth.getPrincipal();
如果那不是完全正确的话,那非常接近.不过要小心,因为如果用户实际上没有登录,则将收到ClassCastException -如果激活了Spring Security匿名过滤器,则对getPrincipal()的调用将返回字符串“ anonymousUser”.您当然可以轻松地更新代码来解决这种可能性.
我们今天的关于Spring-security中UserDetails上的@Autowired返回异常和springsecurity返回错误信息的分享就到这里,谢谢您的阅读,如果想了解更多关于java – Spring Security:未调用自定义UserDetailsService(使用Auth0身份验证)、java – 无法自动连线字段:private org.springframework.security.core.userdetails.UserDetailsService、java-Spring Security 3.1并返回匿名UserDetails、java-Spring Security如何在不登录的情况下更新userDetails的相关信息,可以在本站进行搜索。
本文标签: