I've been struggling to map SecurityConfig file to the newer Spring version. Specifically, the problem (I think) is caused by the UserDetailsService() or something related to it. I'm trying to log in by passing raw password to the login page while encrypted password is hardcoded into the database (I have just pasted the string returned by the encode() method). While trying to do that, I'm getting following message:
Hibernate: select u1_0.id,u1_0.name,u1_0.password,u1_0.username from users u1_0 where u1_0.username=?
Hibernate: select a1_0.user_id,a1_0.id,a1_0.authority from authority a1_0 where a1_0.user_id=?
It looks like id is not passed correctly somewhere but I'm not sure how to feel about it. I just can't log in properly.
Below I'll show you what I'm coming from and what do i have atm, as well as some other files, however they should be fine since there were rather not too many changes to the way they are coded in Spring Boot 3. Anyway, since I'm not sure they might come to be helpful, so here they are:
Old file:
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
// auth.inMemoryAuthentication()
// .passwordEncoder(getPasswordEncoder())
// .withUser("trevor@craftycodr.com")
// .password(getPasswordEncoder().encode("asdfasdf"))
// .roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().hasRole("USER").and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll();
}
}
New file:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig
{
@Autowired
private UserDetailsService userDetailsService;
@Bean
public UserDetailsService userDetailsService()
{
return new UserDetailsServiceImpl();
}
@Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception
{
return
http.authorizeHttpRequests()
.requestMatchers("/").permitAll()
.anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.permitAll()
.and()
.logout()
.logoutUrl("/logout").permitAll()
.and().build();
}
@Bean
public AuthenticationProvider authenticationProvider()
{
DaoAuthenticationProvider authenticationProvider=new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
}
UserDetailsServiceImpl:
@Service
public class UserDetailsServiceImpl implements UserDetailsService
{
@Autowired
private UserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
{
User user = userRepo.findByUsername(username);
if(user == null)
{
throw new UsernameNotFoundException("Invalid username and password");
}
return new CustomSecurityUser(user);
}
}
CustomSecurityUser:
public class CustomSecurityUser extends User implements UserDetails
{
private static final long serialVersionUID = 464958176L;
public CustomSecurityUser()
{}
public CustomSecurityUser(User user)
{
this.setAuthorities(user.getAuthorities());
this.setId(user.getId());
this.setName(user.getName());
this.setPassword(user.getPassword());
this.setUsername(user.getUsername());
}
@Override
public Set<Authority> getAuthorities()
{
return super.getAuthorities();
}
@Override
public String getPassword()
{
return super.getPassword();
}
@Override
public String getUsername()
{
return super.getUsername();
}
@Override
public boolean isAccountNonExpired()
{
return true;
}
@Override
public boolean isAccountNonLocked()
{
return true;
}
@Override
public boolean isCredentialsNonExpired()
{
return true;
}
@Override
public boolean isEnabled()
{
return true;
}
}
UserRepository:
public interface UserRepository extends JpaRepository<User, Long>
{
User findByUsername(String username);
}
Authority:
package com.freshvotes.security;
import org.springframework.security.core.GrantedAuthority;
import com.freshvotes.domain.User;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
@Entity
public class Authority implements GrantedAuthority
{
private static final long serialVersionUID = -6420181486L;
private Long id;
private String authority;
private User user;
@Override
public String getAuthority()
{
return this.authority;
}
public void setAuthority(String authority)
{
this.authority = authority;
}
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId()
{
return this.id;
}
public void setId(Long id)
{
this.id = id;
}
@ManyToOne()
public User getUser()
{
return this.user;
}
public void setUser(User user)
{
this.user = user;
}
}
User entity:
@Entity
@Table(name = "users")
public class User
{
private Long id;
private String username;
private String password;
private String name;
private Set<Authority> authorities = new HashSet<>();
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="user")
public Set<Authority> getAuthorities()
{
return this.authorities;
}
public void setAuthorities(Set<Authority> authorities)
{
this.authorities = authorities;
}
}
I hope it'll be possible to make something out of it. I deleted the imports because i couldn't post my question otherwise.
It appears that there might be an issue with the data in your database. I cloned your repository and conducted a test by adding data, and it seems to be functioning correctly on my end.
To troubleshoot, try using the following credentials on the login page: Username - user
and Password - password
.
Additionally, here are the details of the data I inserted into the database:
User Table:
INSERT INTO users(id, name, password, username) values (1, 'kc', '$2a$10$C6454pQIMqMNW76.M8NjYOzvniTgqdl8unnjnWNnMXmkGqE1M9CSC', 'user');
Authority Table:
INSERT INTO authority(id, authority, user_id) VALUES (1, 'ROLE_USER', 1);
If you're new to this, I recommend adding the following lines to your application properties file. This will enable detailed logging for Spring Security, helping you to trace and debug potential issues:
Add the following line to your application.properties
file:
logging.level.org.springframework.security=TRACE
Additionally, in your WebSecurityConfig
, you can enable debugging by adding debug = true
within the @EnableWebSecurity
annotation. Here's an example:
@EnableWebSecurity(debug = true)
public class WebSecurityConfig {
// Your security configuration code here
}