com.api.WebSecurityConfig 中的字段 myUserDetailsS​​ervice 需要一个 bean,但找到了 2 个

Posted

技术标签:

【中文标题】com.api.WebSecurityConfig 中的字段 myUserDetailsS​​ervice 需要一个 bean,但找到了 2 个【英文标题】:Field myUserDetailsService in com.api.WebSecurityConfig required a single bean, but 2 were found 【发布时间】:2021-04-23 00:50:32 【问题描述】:

完全错误: :

user1:在文件中定义 [/tools/tomcat/instances/webapps/api/WEB-INF/classes/com/api/jwt/users/test1.class] user2:在文件中定义 [/tools/tomcat/instances/webapps/api/WEB-INF/classes/com/api/jwt/users/test2.class]

我有以下课程:

Test1.java

@Service
@Component("user1")
public class Test1 implements UserDetailsService 

    @Value("$test1.username")
    private String test1Username;

    @Value("$test1.password")
    private String test1Password;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        if (username != null && username.equals(test1Username)) 
            return new User(username, test1Password, new ArrayList<>());
         else 
            throw new UsernameNotFoundException("Username not found: " + username);
        
    


Test2.java

@Service
@Component("user2")
public class Test2 implements UserDetailsService 

    @Value("$test2.username")
    private String test2Username;

    @Value("$test2.password")
    private String test2Password;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        if (username != null && username.equals(test2Username)) 
            return new User(username, test2Password, new ArrayList<>());
         else 
            throw new UsernameNotFoundException("Username not found: " + username);
        
    


SpringMainApplication.java

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private UserDetailsService myUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(myUserDetailsService);
    

    @Bean
    public PasswordEncoder passwordEncoder() 
        return NoOpPasswordEncoder.getInstance();
    

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception 
        httpSecurity.csrf().disable()
            .authorizeRequests().antMatchers("/**/access-token").permitAll().
            anyRequest().authenticated().and().
            exceptionHandling().and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    


JwtRequestFilter.java

@Component
public class JwtRequestFilter extends OncePerRequestFilter 

    @Autowired
    @Qualifier(value = "user1")
    private Test1 test1;

    @Autowired
    @Qualifier(value = "user2")
    private Test2 test2;

    @Override
    protected void doFilterInternal() throws ServletException, IOException 
        // SOME CODE
    

我以为通过使用@Component@Qualifier,我可以设置两个用户详细信息类,但似乎并非如此。

有什么我遗漏的或者在这个设计中是不可能的吗?

如果我创建另一个名为 MyUserDetailsService.java 的类,则编译工作正常,并且在各自的端点中访问正确的类。我只是不明白为什么MyUserDetailsService 必须存在并且我不能使用Test1Test2 作为用户类。

编辑:

Test1.java

@Service
@Component("myUserDetailsService")
public class Test1 implements UserDetailsService 

    @Value("$test1.username")
    private String test1Username;

    @Value("$test1.password")
    private String test1Password;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        if (username != null && username.equals(test1Username)) 
            return new User(username, test1Password, new ArrayList<>());
         else 
            throw new UsernameNotFoundException("Username not found: " + username);
        
    


Test2.java

@Service
@Component("myUserDetailsService")
public class Test2 implements UserDetailsService 

    @Value("$test2.username")
    private String test2Username;

    @Value("$test2.password")
    private String test2Password;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        if (username != null && username.equals(test2Username)) 
            return new User(username, test2Password, new ArrayList<>());
         else 
            throw new UsernameNotFoundException("Username not found: " + username);
        
    


SpringMainApplication.java

@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    @Qualifier(value = "myUserDetailsService")
    private UserDetailsService myUserDetailsService;

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(myUserDetailsService);
    

    @Bean
    public PasswordEncoder passwordEncoder() 
        return NoOpPasswordEncoder.getInstance();
    

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception 
        httpSecurity.csrf().disable()
            .authorizeRequests().antMatchers("/**/access-token").permitAll().
            anyRequest().authenticated().and().
            exceptionHandling().and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    


JwtRequestFilter.java

@Component
public class JwtRequestFilter extends OncePerRequestFilter 

    @Autowired
    private Test1 test1;

    @Autowired
    private Test2 test2;

    @Override
    protected void doFilterInternal() throws ServletException, IOException 
        // SOME CODE
    

这给了我以下错误:

org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.api.SpringMainApplication];

nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException:

Annotation-specified bean name 'myUserDetailsService' for bean class [com.api.jwt.users.Test2DetailsService] conflicts with existing, non-compatible bean definition of same name and class [com.api.jwt.users.Test1DetailsService]

【问题讨论】:

【参考方案1】:

这些声明不需要限定符。 Spring 可以按类型注入它们,因为每种类型(Test1 和 Test2)都有一个匹配的 bean。

@Autowired
@Qualifier(value = "user1")
private Test1 test1;

@Autowired
@Qualifier(value = "user2")
private Test2 test2;

但是,您确实需要此声明的限定符,因为您有两个 UserDetailsService 实现,并且 spring 不知道要注入哪一个,从而导致错误。

@Autowired
private UserDetailsService myUserDetailsService;

编辑

在您更新的示例中,您定义了两个具有相同 bean id 的 bean

@Component("myUserDetailsService")
public class Test1 implements UserDetailsService 

@Component("myUserDetailsService")
public class Test2 implements UserDetailsService 

这会导致您看到的新错误(查看Spring documentation 可能会有所帮助):

注解指定的 bean 名称 'myUserDetailsS​​ervice' 用于 bean 类 [com.api.jwt.users.Test2DetailsS​​ervice] 与现有冲突, 相同名称和类的不兼容 bean 定义 [com.api.jwt.users.Test1DetailsS​​ervice]

在您的示例中,拥有两个 UserDetailsService 实现并没有真正意义。您可以通过将它们组合成一个类来重构。

【讨论】:

我编辑了我的问题。你介意再看一下吗? 我认为我遇到的问题是我无法同时加载 user1 和 user2。它是一个或另一个,但我需要加载它们,因为它们有自己特定的令牌秘密和端点。 基本上我的问题是是否有办法在没有MyUserDetailsService 类的情况下使用Test1Test2。现在我有所有 3 个类并且它可以工作,但如果我可以删除 MyUserDetailsService 将是理想的,所以我不会有双重代码。

以上是关于com.api.WebSecurityConfig 中的字段 myUserDetailsS​​ervice 需要一个 bean,但找到了 2 个的主要内容,如果未能解决你的问题,请参考以下文章