Search code examples
springgwtspring-securityrequestfactory

NoSuchBeanDefinitionException when add @PreAuthorize annotation


I'm trying to perform integration of my GWT application and Spring Security. And when I add @PreAuthorize("hasRole('ROLE_USER')") annotation to the method of my DAO class following exception appears:

No unique bean of type [server.dao.ElementServiceDAO] is defined: expected single bean but found 0

DaoServiceLocator can't find DAO bean, but in debug mode I see elementServiceDAO bean in ApplicationContext instance.

My DAO class looks like this:

@Service
public class ElementServiceDAO extends EntityDAO {

@PreAuthorize("hasRole('ROLE_USER')")
@SuppressWarnings("unchecked")
public Layer getFullRenderingTopology() {
...
}

}

DAO service locator's code:

public class DaoServiceLocator implements ServiceLocator {

@Override
public Object getInstance(final Class<?> clazz) {
    try {
        final HttpServletRequest request = RequestFactoryServlet
                .getThreadLocalRequest();

        final ServletContext servletContext = request.getSession()
                .getServletContext();

        final ApplicationContext context = WebApplicationContextUtils
                .getWebApplicationContext(servletContext);

        return context.getBean(clazz);
    } catch (final Exception e) {
        throw new RuntimeException(e);
    }
}
}

applicationContext-security.xml:

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="operator" password="operator" authorities="ROLE_USER, ROLE_ADMIN" />
            <user name="guest" password="guest" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

<global-method-security pre-post-annotations="enabled" /> 

Please give me any advice!


Solution

  • When ElementServiceDAO implements an interface (in your case - transitively via EntityDAO), Spring by default creates an interface-based proxy to apply security aspects. So, elementServiceDAO in your application context is a proxy that isn't instance of ElementServiceDAO, therefore it cannot be retrieved by type.

    You either need to

    • force creation of target-class-based proxies as follows

      <global-method-security 
          pre-post-annotations="enabled" proxy-target-class = "true" /> 
      
    • or create a business interface for ElementServiceDAO and use that interface instead of implementation class.

    See also: