0

spring-boot-starter-security을 사용 중입니다. 내가 WebSecurityConfigationDaoAuthenticationProvider 공급자와 BCryptPasswordEncoder 인증을 사용하도록 구성했습니다. 또한 UserDetailsService 구현은 password 필드가 실제 해시로 설정된 User 개체를 반환합니다.Java Spring Security의 비밀번호 해시로 인증 할 수있는 이유

잘 작동하는 것 같습니다. 그러나 내가 암호를 또는 해시를 사용하여 성공적으로 인증 할 수있는 것으로 나타났습니다.

예를 들어 암호 자체는 생성 된 UUID 51a80a6a-8618-4583-98d2-d77d103a62c6이며 $2a$10$u4OSZf7B9yJvQ5UYNNpy7O4f3g0gfUMl2Xmm3h282W.3emSN3WqxO으로 인코딩되었습니다.

전체 웹 보안 구성 :

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private DemoUserDetailsService userDetailsService; 

    @Autowired 
    private DaoAuthenticationProvider authenticationProvider; 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.authenticationProvider(authenticationProvider); 
     auth.userDetailsService(userDetailsService); 
     auth.inMemoryAuthentication().withUser("user").password("password").roles("SUPER", "BASIC"); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests().antMatchers("/**").hasRole("BASIC").and().httpBasic(); 
     http.csrf().disable(); 
    } 
} 

@Service 
public class DemoUserDetailsService implements UserDetailsService { 

    @Autowired 
    private UserRepository userRepository; 

    @Override 
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { 
     UserDAO userDAO = userRepository.findByEmailAndActivated(email); 
     if (userDAO == null) { 
      throw new UsernameNotFoundException(String.format("Email %s not found", email)); 
     } 
     return new User(email, userDAO.getPasswordHash(), getGrantedAuthorities(email)); 
    } 

    private Collection<? extends GrantedAuthority> getGrantedAuthorities(String email) { 
     return asList(() -> "ROLE_BASIC"); 
    } 
} 

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

@Bean 
public DaoAuthenticationProvider authenticationProvider() { 
    DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); 
    authenticationProvider.setUserDetailsService(userDetailsService); 
    authenticationProvider.setPasswordEncoder(passwordEncoder); 
    return authenticationProvider; 
} 

이유는 두 문자열 인증 할 수 있어요? 내가 잘못한 일을하고 있니? 문서에서 아무 것도 찾을 수 없습니다.

+0

확률은 무엇입니까? 그러나 인코딩 된 문자열을 인코딩하여 확인하십시오.이 결과는 동일한 출력이 될 수 있습니다 (나는 그 사실을 의심합니다). 결과 해시가 고유하지 않기 때문에 가능합니다. 가능하지는 않지만 가능하면 – AxelH

+0

이 구성을 표시합니다. bcrypt에 보안을 구현했기 때문에이 사실을 전혀 알지 못합니다. –

+0

@shutdown -h 이제 어떤 구성을 의미합니까? – Tom

답변

1

DaoAuthenticationProvider

protected void additionalAuthenticationChecks(UserDetails userDetails, 
      UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { 
     Object salt = null; 

     if (this.saltSource != null) { 
      salt = this.saltSource.getSalt(userDetails); 
     } 

     if (authentication.getCredentials() == null) { 
      logger.debug("Authentication failed: no credentials provided"); 

      throw new BadCredentialsException(messages.getMessage(
        "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails); 
     } 

     String presentedPassword = authentication.getCredentials().toString(); 

     if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) { 
      logger.debug("Authentication failed: password does not match stored value"); 

      throw new BadCredentialsException(messages.getMessage(
        "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"), userDetails); 
     } 
    } 

이 대표의 additionalAuthenticationChecks 방법에 에스. 하나는 명시 적이며 사용자가 구성하고 암시 적으로 하나는 auth.userDetailsService(userDetailsService);을 호출 할 때 후드에서 구성되며 암시 적 공급자의 경우 암호 엔코더를 설정하지 않습니다.

@Override 
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); 
    auth.inMemoryAuthentication().withUser("user").password("password").roles("SUPER", "BASIC"); 
} 

을 그리고 당신을 수동으로 구성 공급자를 제거 - 당신이 실제로있어 그것을 필요가없는 것 같습니다 :

이것 좀보십시오.

희망이 있습니다.

+0

사실 당신 말이 맞아요. 추가 (userDetailsService) .passwordEncoder (새 BCryptPasswordEncoder()); 도와 줬어. – Tom

-1

가장 좋은 방법은 디버거를 연결하는 것입니다. 비밀번호를 일치하는되는 PasswordEncoder 사용의 실제 논리는 내가 당신의 설정에 따라 실제로 두 DaoAuthenticationProvider를 얻을 수 있기 때문에이 일이 어떻게 생각 BCryptPasswordEncoder

public boolean matches(CharSequence rawPassword, String encodedPassword) { 
     if (encodedPassword == null || encodedPassword.length() == 0) { 
      logger.warn("Empty encoded password"); 
      return false; 
     } 
    if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) { 
     logger.warn("Encoded password does not look like BCrypt"); 
     return false; 
    } 

    return BCrypt.checkpw(rawPassword.toString(), encodedPassword); 
} 
+1

감사하지만 이것은 답변이 아닙니다. – Tom