Spring Security中如何在内存身份验证和jdbc身份验证中同时配置

时间:2019-09-03 01:39:27

标签: java spring spring-mvc spring-security

我可以通过以下配置实现内存认证

export http_proxy=http://xx.xx.xxx.xxx:xxxx; export https_proxy=...

通过以下配置(在不同项目中)进行jdbc身份验证

curl -I https://rubygems.org

当我试图在同一个项目中实现这两个目标时(我只是在SpringSecurityConfig中添加了configureInMemoryAuthentication和configureJdbcAuthentication方法,如下所示)

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{

    @Autowired
    public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.inMemoryAuthentication().withUser("praveen").password("{noop}praveen@123#").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("vedanta").password("{noop}vedanta@123#").roles("USER");
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception
    {
        http
            .authorizeRequests()
                .antMatchers("/resources/**", "/", "/login", "/api/**").permitAll()
                .antMatchers("/app/admin/*").hasRole("ADMIN").antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
            .and().exceptionHandling().accessDeniedPage("/403")
            .and().formLogin()
                .loginPage("/login").usernameParameter("userName")
                .passwordParameter("password")
                .defaultSuccessUrl("/app/user/dashboard")
                .failureUrl("/login?error=true")
            .and().logout()
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .invalidateHttpSession(true)
            .and().csrf().disable();

        http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
    }
}

但是我无法成功使用inMemoryAuthentication凭据登录,我已被重定向到“ / login?error = true”页面。

但是我能够使用jdbcAuthentication凭据成功登录。

但不能同时实现两者。
我做错什么了吗?
是否可以将两个身份验证结合在一起?

1 个答案:

答案 0 :(得分:0)

Mistake是,身份验证管理器正在尝试对我的纯密码进行解码并发出此警告。

WARN  - Encoded password does not look like BCrypt

看到日志后,我尝试password("{noop}restapiuser@123#")也不起作用,可能是因为jdbcAuthentication已为passwordEncoder注册,身份验证管理器将每次都尝试解密/解码密码。因此,无需跳过密码解码的任何方式都无需提供编码后的密码。

由于我没有保留编码的密码,因此它尝试对其进行解码并重定向到failureUrl。

参考解决方案

@Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
    auth.inMemoryAuthentication()
    .withUser("restapiuser")
    .password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
    .roles("APIUSER");
}

或者,最佳做法是保留编码密码而不是普通密码

.password("$2a$10$GRoNCbeVoBYMcZH7QLX2O.wWxkMtB4qiBY8y.XzvRN/mvktS9GWc6")

替代。只有一种configureAuthentication方法,但同时在内存和jdbc身份验证中进行如下配置

@Autowired
public void configureBothAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
    auth.inMemoryAuthentication()
        .withUser("restapiuser")
        .password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
        .roles("ADMIN");

    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
            .usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
            .authoritiesByUsernameQuery(
                    "select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId  where username = ?");
}

所以,
在春季项目中可以同时实现InMemoryAuthentication和jdbcAuthentication。