问题
I am using spring security with BCrypt Password encoder for authentication. when i want to login, Spring security fetchs user data with JPA correctly but for checking raw password with encoded password it gives null string as encoded password to password encoder.
spring security config :
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder(){
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasAuthority("USER")
.antMatchers("/css/**","/font/**","/js/**","/image/**").permitAll()
.antMatchers("/register").permitAll()
.and().formLogin().loginPage("/login").successForwardUrl("/").permitAll()
.and().logout().logoutSuccessUrl("/login");
}
}
userDetailsServise :
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private UserRepository userRepo;
@Autowired
public UserDetailsServiceImpl(UserRepository userRepo){
this.userRepo = userRepo;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findByUsername(username);
if(user != null) {
System.out.println(user.toString());
return user;
}
throw new UsernameNotFoundException("User "+ username +" not found");
}
}
user entity:
@Entity
@Table(name = "users")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "users_id_seq",allocationSize = 1)
private long id;
@NotEmpty
@Column(nullable = false, unique=true)
private String username;
@Email
@Column(nullable = false, updatable = false, unique = true)
private String email;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private boolean enabled;
@CreationTimestamp
@Column(name = "creation_time")
private Timestamp creationTime;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(joinColumns = @JoinColumn(name="user_id"))
private List<Authority> authorities;
...
logs:
2019-05-31 19:51:58.888 DEBUG 7181 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
2019-05-31 19:51:58.889 DEBUG 7181 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2019-05-31 19:51:59.245 DEBUG 7181 --- [nio-8080-exec-3] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-05-31 19:51:59.388 INFO 7181 --- [nio-8080-exec-3] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_1_, user0_.creation_time as creation2_1_, user0_.email as email3_1_, user0_.enabled as enabled4_1_, user0_.password as password5_1_, user0_.username as username6_1_ from users user0_ where user0_.username=?
Hibernate: select authoritie0_.user_id as user_id1_0_0_, authoritie0_.authorities as authorit2_0_0_ from user_authorities authoritie0_ where authoritie0_.user_id=?
User{
id=8
, username='username'
, email='mail@example.com'
, password='$2a$10$TyQ8x0KUP9Nrtzo2ljfNfei4S3h1kFpYEb5/CDs2lKSDzMJECQ./q'
, enabled=true
, creationTime=2019-05-31 19:32:12.948
, authorities=[USER]}
2019-05-31 19:51:59.758 WARN 7181 --- [nio-8080-exec-3] o.s.s.c.bcrypt.BCryptPasswordEncoder : Empty encoded password
2019-05-31 19:51:59.758 DEBUG 7181 --- [nio-8080-exec-3] o.s.s.a.dao.DaoAuthenticationProvider : Authentication failed: password does not match stored value
2019-05-31 19:51:59.773 DEBUG 7181 --- [nio-8080-exec-3] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
I create following password encoder and I figure out that spring security gives a null string as encoded password to password encoder.
@Component
public class MyPasswordEncoder implements PasswordEncoder {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
@Override
public String encode(CharSequence rawPassword) {
return encoder.encode(rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
System.out.println("raw password: " + rawPassword + "\t encoded passwod: "+ encodedPassword);
return encoder.matches(rawPassword,encodedPassword);
}
}
logs with custom password encoder:
2019-06-01 03:19:52.759 DEBUG 7870 --- [nio-8080-exec-5] w.a.UsernamePasswordAuthenticationFilter : Request is to process authentication
2019-06-01 03:19:52.759 DEBUG 7870 --- [nio-8080-exec-5] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2019-06-01 03:19:53.036 DEBUG 7870 --- [nio-8080-exec-5] tor$SharedEntityManagerInvocationHandler : Creating new EntityManager for shared EntityManager invocation
2019-06-01 03:19:53.095 INFO 7870 --- [nio-8080-exec-5] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select user0_.id as id1_1_, user0_.creation_time as creation2_1_, user0_.email as email3_1_, user0_.enabled as enabled4_1_, user0_.password as password5_1_, user0_.username as username6_1_ from users user0_ where user0_.username=?
Hibernate: select authoritie0_.user_id as user_id1_0_0_, authoritie0_.authorities as authorit2_0_0_ from user_authorities authoritie0_ where authoritie0_.user_id=?
User{
id=8
, username='username'
, email='mail@example.com'
, password='$2a$10$TyQ8x0KUP9Nrtzo2ljfNfei4S3h1kFpYEb5/CDs2lKSDzMJECQ./q'
, enabled=true
, creationTime=2019-05-31 19:32:12.948
, authorities=[USER]}
raw password: password encoded passwod: null
2019-06-01 03:19:53.413 WARN 7870 --- [nio-8080-exec-5] o.s.s.c.bcrypt.BCryptPasswordEncoder : Empty encoded password
2019-06-01 03:19:53.413 DEBUG 7870 --- [nio-8080-exec-5] o.s.s.a.dao.DaoAuthenticationProvider : Authentication failed: password does not match stored value
2019-06-01 03:19:53.415 DEBUG 7870 --- [nio-8080-exec-5] w.a.UsernamePasswordAuthenticationFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
full source on github : https://github.com/yrostami/spring_sample
回答1:
BCryptPasswordEncoder
will compare the password from the loaded user with the password entered from the login form to see if they match. If the former is null , it will give Empty encoded password
warning.
So by looking at how you load the users , it turns out that your UserDetailsService
will always return an User
with a null password because you hardcode it in getPassword()
(Btw, getUsername()
also has the same problem). So change to following should fix it :
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.username;
}
来源:https://stackoverflow.com/questions/56397924/why-spring-security-gives-empty-password-to-password-encoder