使用UserCredentialsDataSourceAdapter 作为@"M. Deinum" 建议使用某种过滤器或处理AuthenticationSuccessEvent。
基本上你应该用当前主体username 和password 调用setCredentialsForCurrentThread 方法。
您必须禁用身份验证管理器的凭据擦除才能在身份验证后检索用户密码。
@EnableWebSecurity
public static class Security extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.eraseCredentials(false) // for password retrieving
.inMemoryAuthentication()
.withUser("postgres").password("postgres1").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().mvcMatchers("/").fullyAuthenticated();
}
}
数据源适配器:
@Bean
public UserCredentialsDataSourceAdapter dataSource(DataSourceProperties properties) {
final UserCredentialsDataSourceAdapter dataSourceAdapter = new UserCredentialsDataSourceAdapter();
dataSourceAdapter.setTargetDataSource(DataSourceBuilder.create()
.driverClassName(properties.getDriverClassName())
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.type(SimpleDriverDataSource.class) // disable pooling
.build());
((SimpleDriverDataSource) dataSourceAdapter.getTargetDataSource()).setDriverClass(org.postgresql.Driver.class); //binder won't set it automatically
return dataSourceAdapter;
}
AuthenticationSuccessHandler:
@Component
public static class AuthenticationHandler /*implements ApplicationListener<AuthenticationSuccessEvent> use that if your spring version is less than 4.2*/ {
private final UserCredentialsDataSourceAdapter dataSourceAdapter;
@Autowired
public AuthenticationHandler(UserCredentialsDataSourceAdapter dataSourceAdapter) {
this.dataSourceAdapter = dataSourceAdapter;
}
@EventListener(classes = AuthenticationSuccessEvent.class)
public void authenticationSuccess(AuthenticationSuccessEvent event) {
final Authentication authentication = event.getAuthentication();
final User user = (User) authentication.getPrincipal();
dataSourceAdapter.setCredentialsForCurrentThread(user.getUsername(), user.getPassword()); // <- the most important part
}
}
或者您可以使用Filter 代替事件监听器:
@Component
public static class DataSourceCredentialsFilter extends GenericFilterBean {
private final UserCredentialsDataSourceAdapter dataSourceAdapter;
@Autowired
public DataSourceCredentialsFilter(UserCredentialsDataSourceAdapter dataSourceAdapter) {
this.dataSourceAdapter = dataSourceAdapter;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
final User user = (User) authentication.getPrincipal();
dataSourceAdapter.setCredentialsForCurrentThread(user.getUsername(), user.getPassword());
chain.doFilter(request, response);
dataSourceAdapter.removeCredentialsFromCurrentThread();
}
}
查看完整示例here。