【问题标题】:Authentication failed: password does not match stored value (see update 2)身份验证失败:密码与存储的值不匹配(请参阅更新 2)
【发布时间】:2014-09-21 23:52:25
【问题描述】:

在我当前的spring项目中,我有以下安全配置:

@Configuration
@ComponentScan(value="com.spring.loja")
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private SocialUserDetailsService socialUserDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public void configure(WebSecurity web) throws Exception {
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new CustomPermissionEvaluator());
        web.expressionHandler(handler);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .disable()
            .authorizeRequests()
                .antMatchers("/resources/**", "/erro/**", "/categoria/**", "/produto/**", "/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/entrar").permitAll()
                .loginProcessingUrl("/login").permitAll()
                .usernameParameter("login")
                .passwordParameter("senha")
                .defaultSuccessUrl("/admin")
                .failureUrl("/entrar?erro=login").permitAll()
                .and()
            .exceptionHandling()
                .accessDeniedPage("/erro/403")
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/").permitAll()
                .and()
            .apply(new SpringSocialConfigurer());
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

当我运行应用程序并尝试登录时,系统会返回登录页面,即使使用正确的登录凭据(我很确定)。

任何人都可以看到这里出了什么问题?

更新

我也试试这个,同样的问题。在我看来,此配置无法访问我的 userDetailsS​​ervice 类,应通过此类中的 autowired 属性检索该类:

@Configuration
@ComponentScan(value="com.spring.loja")
@EnableGlobalMethodSecurity(prePostEnabled=true)
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private SocialUserDetailsService socialUserDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManagerBuilder auth;

    @Override
    public void configure(WebSecurity web) throws Exception {
        DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
        handler.setPermissionEvaluator(new CustomPermissionEvaluator());
        web.expressionHandler(handler);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .disable()
            .authorizeRequests()
                .antMatchers("/resources/**", "/erro/**", "/categoria/**", "/produto/**", "/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/entrar").permitAll()
                .loginProcessingUrl("/login").permitAll()
                .usernameParameter("login")
                .passwordParameter("senha")
                .defaultSuccessUrl("/admin")
                .failureUrl("/entrar?erro=login").permitAll()
                .and()
            .exceptionHandling()
                .accessDeniedPage("/erro/403")
                .and()
            .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/").permitAll()
                .and()
            .apply(new SpringSocialConfigurer());
    }

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return auth.getOrBuild();
    }

}

更新 2

配置 log4j 后,我发现错误是密码与存储的值不匹配。问题是我确保存储在数据库中的密码被编码为 MD5,而我的 PasswordEncoder bean 是这样的:

@Component
public class BCryptPasswordEncoder implements PasswordEncoder {

    @Override
    public String encode(CharSequence arg0) {
        try {
            return getMD5Hex((String) arg0);
        } catch (NoSuchAlgorithmException e) {
            return "NoSuchAlgorithmException";
        }
    }

    @Override
    public boolean matches(CharSequence arg0, String arg1) {
        return arg0.equals(encode(arg1));
    }

    public static String getMD5Hex(final String inputString) throws NoSuchAlgorithmException {

        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(inputString.getBytes());

        byte[] digest = md.digest();

        return convertByteToHex(digest);
    }

    private static String convertByteToHex(byte[] byteData) {

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < byteData.length; i++) {
            sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }

        return sb.toString();
    }

}

我明确告诉我要使用 MD5。这里有什么问题?

ps.:我也注意到应用程序没有使用我在 SEcurityConfig 类中定义的 authenticationManager bean(问题中的第二个列表)

【问题讨论】:

  • 能否提供spring security的调试日志?
  • @coder 你建议什么?
  • 目前您的应用中配置了任何日志记录?
  • @coder 不,我尝试过一次 log4j,但无法将其设置到我的系统中。
  • @coder 在配置 log4j 后,我发现我的问题是密码与存储的值不匹配。我的问题是我确定存储的值是用 MD5 编码的。我只是更新问题以包括我的 PasswordEncoder。你能说出这里出了什么问题吗?

标签: java spring spring-mvc spring-security


【解决方案1】:

org.springframework.security.crypto.password.PasswordEncoder 匹配方法有签名

boolean matches(CharSequence rawPassword, String encodedPassword);

所以这意味着 arg0 是用户输入的密码,而 arg1 是您保存在数据库中的编码密码。 所以实现应该是

 public boolean matches(CharSequence rawPassword, String encodedPassword) {
            return encodedPassword.equals(encode(rawPassword));
 }

由于您使用了不正确的参数序列,因此您在 match 方法中再次对编码密码进行编码。 使用有意义的名称而不是 arg0、arg1 是一种很好的做法,以避免混淆。

【讨论】:

    猜你喜欢
    • 2015-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    相关资源
    最近更新 更多