taglibs sec hasrole java spring spring-security vaadin spring-jdbc

java - hasrole - Spring Security dependencia de frijol circular



spring security tags (2)

Prefiero el método @Lazy. De esa forma puedo mantener un patrón.

Ver http://www.baeldung.com/circular-dependencies-in-spring

Actualmente estoy trabajando en una aplicación de primavera Vaadin. Lo único que puedo decir es que la autenticación / autorización de los usuarios debe realizarse consultando la base de datos a través de jdbcTemplate . ¿Cómo resolver este problema? Estoy usando Spring Boot 1.4.2.RELEASE.

Description: The dependencies of some of the beans in the application context form a cycle: ┌─────┐ | jdbcAccountRepository defined in file [repositories/JdbcAccountRepository.class] ↑ ↓ | securityConfiguration.WebSecurityConfig (field services.JdbcUserDetailsServicessecurity.SecurityConfiguration$WebSecurityConfig.userDetailsService) ↑ ↓ | jdbcUserDetailsServices (field repositories.JdbcAccountRepository services.JdbcUserDetailsServices.repository) └─────┘

El código original se ve así:

AccountRepository:

public interface AccountRepository { void createAccount(Account user) throws UsernameAlreadyInUseException; Account findAccountByUsername(String username); }

JdbcAccountRepository:

@Repository public class JdbcAccountRepository implements AccountRepository { private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); private final JdbcTemplate jdbcTemplate; private final PasswordEncoder passwordEncoder; @Autowired public JdbcAccountRepository(JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) { this.jdbcTemplate = jdbcTemplate; this.passwordEncoder = passwordEncoder; } @Transactional @Override public void createAccount(Account user) throws UsernameAlreadyInUseException { try { jdbcTemplate.update( "insert into Account (firstName, lastName, username, password, role) values (?, ?, ?, ?, ?)", user.getFirstName(), user.getLastName(), user.getUsername(), passwordEncoder.encode( user.getPassword()), user.getRole() ); } catch (DuplicateKeyException e) { throw new UsernameAlreadyInUseException(user.getUsername()); } } @Override public Account findAccountByUsername(String username) { return jdbcTemplate.queryForObject( "select username, password, firstName, lastName, role from Account where username = ?", (rs, rowNum) -> new Account( rs.getString("username"), rs.getString("password"), rs.getString("firstName"), rs.getString("lastName"), rs.getString("role")), username ); } }

JdbcUserDetailsServices:

@Service public class JdbcUserDetailsServices implements UserDetailsService { private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); @Autowired JdbcAccountRepository repository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { try { Account account = repository.findAccountByUsername(username); User user = new User( account.getUsername(), account.getPassword(), AuthorityUtils.createAuthorityList( account.getRole() ) ); return user; } catch (DataAccessException e) { LOGGER.debug("Account not found", e); throw new UsernameNotFoundException("Username not found."); } } }

Configuración de seguridad:

@Configuration @ComponentScan public class SecurityConfiguration { @Autowired ApplicationContext context; @Autowired VaadinSecurity security; @Bean public PreAuthorizeSpringViewProviderAccessDelegate preAuthorizeSpringViewProviderAccessDelegate() { return new PreAuthorizeSpringViewProviderAccessDelegate(security, context); } @EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true) public static class GlobalMethodSecurity extends GlobalMethodSecurityConfiguration { @Bean @Override protected AccessDecisionManager accessDecisionManager() { return super.accessDecisionManager(); } } @Configuration @EnableWebSecurity public static class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired JdbcUserDetailsServices userDetailsService; @Autowired DataSource dataSource; @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean public TextEncryptor textEncryptor() { return Encryptors.noOpText(); } /* * (non-Javadoc) * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter * #configure(org.springframework.security.config.annotation.web.builders.WebSecurity) */ @Override public void configure(WebSecurity web) throws Exception { //Ignoring static resources web.ignoring().antMatchers("/VAADIN/**"); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } @Bean(name="authenticationManager") @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } /* * (non-Javadoc) * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter * #configure(org.springframework.security.config.annotation.web.builders.HttpSecurity) */ @Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling() .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")) .and() .authorizeRequests() .antMatchers("/**").permitAll() .and() .csrf().disable(); } } }

PD Si se baja la versión Spring Boot a [1.1.5,1.2.0), este problema no ocurrirá (debido a otra dependencia, debo usar la última)


Puede reemplazar la inyección de dependencia basada en el constructor con la inyección de dependencia basada en el instalador para resolver el ciclo; consulte la documentación de referencia de Spring Framework :

Dependencias circulares

Si utiliza predominantemente inyección de constructor, es posible crear un escenario de dependencia circular no resuelto.

Por ejemplo: la clase A requiere una instancia de la clase B a través de la inyección del constructor, y la clase B requiere una instancia de la clase A mediante la inyección del constructor. Si configura los beans para las clases A y B para que se inyecten entre sí, el contenedor Spring IoC detecta esta referencia circular en tiempo de ejecución y arroja BeanCurrentlyInCreationException .

Una posible solución es editar el código fuente de algunas clases para ser configuradas por los setters en lugar de los constructores. Alternativamente, evite la inyección del constructor y use solo inyección setter. En otras palabras, aunque no se recomienda, puede configurar dependencias circulares con inyección setter.

A diferencia del caso típico (sin dependencias circulares), una dependencia circular entre el bean A y el bean B fuerza a uno de los beans a inyectarse en el otro antes de que se inicialice por completo (un escenario clásico de pollo / huevo).