GVKun编程网logo

Spring-security中UserDetails上的@Autowired返回异常(springsecurity返回错误信息)

10

本文的目的是介绍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返回错误信息)

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身份验证)

java – Spring Security:未调用自定义UserDetailsService(使用Auth0身份验证)

我是 Spring框架的新手,所以我提前为我理解中的任何漏洞道歉.

我正在使用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复制的自定义数据库支持的UserDetailsS​​ervice.
然而,无论我如何尝试将其添加到我的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的回答,我尝试复制他的CustomUserDetailsS​​ervice,并将以下内容添加到我的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 );
}

不幸的是,通过这些更改,仍未调用CustomUserDetailsS​​ervice.

编辑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

解决方法

查看您的适配器代码,您将在配置中生成JWT令牌.
我不知道什么是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

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可以找到您的UserDetailsS​​ervice.

该应用程序还有一个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实例.

鉴于上述信息,您应将UserDetailsS​​ervice声明及其所有依赖bean移动到getRootConfigClasses.这将确保SecurityConfig.java可以找到UserDetailsS​​ervice.

拉请求修复

我已经提交了一个公关,以获得您的应用程序,使其从没有错误https://github.com/worldcombined/AnnotateFailed/pull/1开始.几个笔记

>测试不使用父和子上下文,因此它不反映运行应用程序
>我不得不移动资源文件夹,以便被正确地拾起
>我没有这样做,所以你实际上可以认证.没有login.jsp,你提供的UserDetailsS​​ervice总是返回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

java-Spring Security 3.1并返回匿名UserDetails

我试图找出如何让Spring Security为该调用返回匿名用户的UserDetails对象:

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

我知道没有特殊配置,该调用将返回一个字符串,而不是您使用自定义UserDetailsS​​ervice实现创建的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>

基于您在此处看到的代码的任何其他建议都将受到欢迎.

最佳答案
对于要从​​匿名用户的UserDetails中提取哪些数据,您实际上并没有提供太多详细信息.如果只想检查用户名,则可以使用Authentication.getName().

无论如何,如果您需要更详细的访问安全性上下文,最好使用自定义接口将应用程序代码与Spring Security类分离(请参见my answer on using a security context accessor).这样,您应该只在一个地方检查主体的类型,而不是在要访问用户数据的“各处”重复检查.

如果您绝对希望身份验证对象中始终具有相同的主体类型,而不管用户是否匿名,那么您将必须通过命名空间禁用匿名身份验证,并基于现有的AnonymousAuthenticationFilter添加自定义过滤器来执行此工作.

java-Spring Security如何在不登录的情况下更新userDetails

java-Spring Security如何在不登录的情况下更新userDetails

我是Spring Security的新手.
我已经实现了UserDetails来创建自己的用户.我也有自定义的userDetailsS​​ervice.现在一切正常,但是我需要在不登录的情况下更新有关用户的信息.如何做到这一点?如何从上下文中接收信息然后进行更改?
 提前致谢

最佳答案
如果用户未登录,则无法从SecurityContext获取该用户.登录过程使用户处于上下文中.

只需使用UserDetailsS​​ervice加载用户(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的相关信息,可以在本站进行搜索。

本文标签: