Search code examples
springspring-securityspring-annotationsspring-bean

spring application-security configuration bean scan


In my project, I needed a custom userDetailsService, So I declaire it like this in certain package:

@Service
@Ihm(name = "userDetailsService")// ignore Ihm, it's just a custom annotation, which works fine
public class UserDetailsServiceImpl implements UserDetailsService 

And in my application-security.xml file, I added component-scan,

<context:component-scan base-package="path(including the userDetailsService for sure)" />

<context:annotation-config />

which didn't help me find my annotated bean, I got bean no defined exception.

The only way worked in my case is : 1.remove the service annotation 2.create the bean in the application-security.xml with beans:bean,id,class. this works fine.

What's more funny is this, when I kept both the component-scan, and the annotation, I got an ID duplicated(more than one bean, ask to specify the ID) error.

 More than one UserDetailsService registered. Please use a specific Id reference in <remember-me/> <openid-login/> or <x509 /> elements.

So this means the @Service did create the bean, but y won't the security.xml find it?


Solution

  • Spring Security is auto wiring beans on bean names, for the UserDetailsService that is userDetailsService.

    @Service
    public class UserDetailsServiceImpl implements UserDetailsService 
    

    The code above (like your code) will lead to a bean of the type UserDetailsService however the name is userDetailsServiceImpl and not userDetailsService and hence your bean is never used by Spring Security nor detected by it. (See Spring Reference Guide for naming conventions_

    To fix this either change the spring security configuration and put in a reference to your userDetailsServiceImpl bean

    <authentication-manager>
        <authentication-provider user-service-ref='userDetailsServiceImpl'/>
    </authentication-manager>
    

    or change the name of your bean by providing the name in the @Service annotation.

    @Service("userDetailsService")
    public class UserDetailsServiceImpl implements UserDetailsService 
    

    Either way will work.

    Links

    1. Using other authentication providers
    2. Naming autodetected components