【问题标题】:Spring boot HTTP Basic pass through to JDBCSpring boot HTTP Basic 传递给 JDBC
【发布时间】:2017-12-03 19:51:56
【问题描述】:

我已配置 JDBC 数据源并自动装配 JDBCTemplate 以执行自定义 SQL 查询。我还有一个简单的 HTTP Basic 身份验证:

auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");

但是,我想使用用于 HTTP Basic 的用户和密码来验证用户对数据库本身的身份,即通过 HTTP Basic 的凭据传递到数据源并以登录的用户身份执行查询HTTP 基本身份验证。我在这里面临两个问题,一个是用户名和密码在 application.properties 文件中,我想在每次用户进行身份验证时覆盖它,并且(重新加载?)以该用户身份执行查询,而不是在属性文件。

更新 1:

我可以像下面这样以编程方式使用用户名和密码:

@Bean
@Primary
public DataSource dataSource() {
    return DataSourceBuilder
        .create()
        .username("")
        .password("")
        .url("")
        .driverClassName("")
        .build();
}

但是每次用户使用这些凭据使用 HTTP 基本身份验证登录时如何调用它?

【问题讨论】:

  • 用jdbcAuthentication代替inMemoryAuthentication怎么样?
  • jdbcAuthentication 是用来登录数据源的吧?如何传递从 Web 请求中收到的凭据?
  • jdbcAuthentication 用于针对您的数据库(假设拥有可以登录到您的应用程序的用户)对最终用户进行身份验证。您需要硬编码每个可以登录的用户,而不是您使用的 inMemoryAuthentication。
  • 如果我不清楚,我很抱歉。假设我们想以 root 身份连接到 MySQL。我希望最终用户为这个用户名 root 提供其来自 HTTP Basic 的密码,然后使用这些密码直接对数据库本身进行身份验证。不在表中检查该用户。
  • 使用UserCredentialsDataSourceAdapter 并在身份验证后(当Authentication 可用时,在此适配器上设置凭据(并且不要忘记在请求完成后清除它们)。

标签: java spring spring-boot basic-authentication


【解决方案1】:

使用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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-12
    • 2018-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 2015-03-18
    • 2017-10-28
    • 1970-01-01
    相关资源
    最近更新 更多