gpt4 book ai didi

java - Spring Security 循环 bean 依赖

转载 作者:IT老高 更新时间:2023-10-28 13:50:26 54 4
gpt4 key购买 nike

我目前正在开发一个 Vaadin spring 应用程序。根据应用规范,用户的认证/授权必须通过jdbcTemplate查询数据库来完成。如何解决这个问题?我正在使用 Spring Boot 1.4.2.RELEASE。

更新:此方法适用于 Spring Boot 1.1.x.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)
└─────┘

原始代码如下所示:

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
);
}
}

JdbcUserDetailsS​​ervices:

@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.");
}
}
}

安全配置:

@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();
}
}
}

P.S 如果将 Spring Boot 版本降级为 [1.1.5,1.2.0) ,则不会出现此问题(由于其他依赖,我必须使用最新的)

最佳答案

您可以替换 constructor-based dependency injectionsetter-based dependency injection要解决该循环,请参阅 Spring Framework Reference Documentation :

Circular dependencies

If you use predominantly constructor injection, it is possible to create an unresolvable circular dependency scenario.

For example: Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException.

One possible solution is to edit the source code of some classes to be configured by setters rather than constructors. Alternatively, avoid constructor injection and use setter injection only. In other words, although it is not recommended, you can configure circular dependencies with setter injection.

Unlike the typical case (with no circular dependencies), a circular dependency between bean A and bean B forces one of the beans to be injected into the other prior to being fully initialized itself (a classic chicken/egg scenario).

关于java - Spring Security 循环 bean 依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40695893/

54 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com