在 Spring 安全中使用 PasswordEncoder 后得到不同的编码密码

Getting different encoded password after using PasswordEncoder in Spring security

我正在尝试从 android 应用程序执行身份验证。我基本上是将用户名和密码(未编码)发送到我的其余 api 端点,即:/api/management/login 我正在使用 Retrofit)。之后,我检查用户是否存在,如果存在则 return 对象,如果存在则 null not.I 注意到编码密码与存储在我的数据库中的密码不同即使初始密码字符串相同。我读到 PasswordEncoder 接口正在生成随机盐以对密码进行编码。有没有办法让盐变得独一无二? 这是我的 spring 安全配置文件:


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private UserPrincipalDetailsService userPrincipalDetailsService;

    public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService) {
        this.userPrincipalDetailsService = userPrincipalDetailsService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


            http.csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(new Http403ForbiddenEntryPoint() {}).and()
            .authenticationProvider(authenticationProvider())
            .authorizeRequests()
                .antMatchers("/management/*").hasRole("ADMIN")
                .antMatchers("/*").hasRole("ADMIN")
                .antMatchers("/management/professor*").hasRole("ADMIN")
                .antMatchers("/management/absence*").hasRole("ADMIN")
                .antMatchers("/management/room*").hasRole("ADMIN")
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .loginProcessingUrl("/signin").permitAll()
                .loginPage("/login").permitAll()
                .successHandler(mySimpleUrlAuthenticationHandler())
                .failureUrl("/login?error=true")
                .usernameParameter("username")
                .passwordParameter("password")
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
                .and()
                .rememberMe().userDetailsService(userPrincipalDetailsService).rememberMeParameter("checkRememberMe");
    }

    @Bean
    DaoAuthenticationProvider authenticationProvider(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);

        return daoAuthenticationProvider;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    MySimpleUrlAuthenticationHandler mySimpleUrlAuthenticationHandler() {
        return new MySimpleUrlAuthenticationHandler();
    }
}

有什么建议吗?

我认为您正在对从客户端收到的密码进行编码,并将其硬编码到 SQL 带有登录 ID 的查询中。如果我的假设是正确的,请不要那样做。

如你所说

I check if the user exists or not and return the object if it does or null if it does not

不要对密码进行编码并将其连接到 SQL 查询(在 /login API 中)。相反,仅根据登录 ID 检索数据。如果它 returns 一个对象,那么显然它 returns 一个编码的密码。现在您需要将已经编码的密码与从客户端收到的纯密码进行比较。

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

BCryptPasswordEncoder encoded = BCryptPasswordEncoder();
boolean matches = encoder.matches("plain password from client", "encoded password here");

if (matches) {
   // successull login
} else {
   // invalid login credentials
}

更多内容请参考BCryptPasswordEncoder#matches() SpringBoot doc