I have a project like platform for online food spring ordering system I am using Hibernate with two Models like this:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
private Long balance;
}
@Entity
@Table(name = "user_roles")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
I think this system has three roles: ROLE_SYSADMIN, ROLE_ADMIN (for food store), ROLE_CUSTOMER Users and UsersRole stored in Database.
How can I config authorization and authentication for my app using Spring Boot 6?
I searched and made some codes. Firstly, I wrote a custom UserDetailService like this
@Service
public class HiruezUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public HiruezUserDetailsService(UserRepository userRepository) {
super();
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
return new HiruezUserDetails(user);
}
}
Then, custom UserDetails like:
public class HiruezUserDetails implements UserDetails {
/**
*
*/
private static final long serialVersionUID = 1L;
private final User user;
public HiruezUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority("ROLE_" + user.getRole().getName()));
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
The last is SecurityConfig.java like:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private HiruezUserDetailsService hiruezUserDetailsService;
@Bean
public PasswordEncoder passwordEncoder( ) {
return new BCryptPasswordEncoder();
}
@Bean
public JdbcUserDetailsManager jdbcUserDetailManager() {
JdbcUserDetailsManager userDetailManager = new JdbcUserDetailsManager();
userDetailManager.setJdbcTemplate(jdbcTemplate);
return userDetailManager;
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(hiruezUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/admin/**").hasRole("SYSADMIN")
.requestMatchers("/store/**").hasRole("ADMIN")
.requestMatchers("/customer/**").hasRole("CUSTOMER")
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout.logoutUrl("/logout"));
return http.build();
}
}
But I work.... ummmm
Please, help me fix or give me another approach. Thank you very much....
let see how we can solve this
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "users")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
private Long balance;
private Long roleId; // new field , this field will set when admin create user by selecting role
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
//authorities.add(new SimpleGrantedAuthority("ROLE_SYSADMIN"));
//authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
//authorities.add(new SimpleGrantedAuthority("ROLE_CUSTOMER"));
// we will set the permission leater
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
public interface UserRepository extends JpaRepository<User, Long> {
}
@Entity
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "user_roles")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
public interface UserRoleRepository extends JpaRepository<UserRole, Long> {
}
@Component
@RequiredArgsConstructor
public class UserAuthenticationProvider implements AuthenticationProvider, UserDetailsService {
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED" : authentication.getName();
if (Utils.isEmpty(username)) {
throw new BadCredentialsException("invalid login details");
}
// get user details using Spring security user details service
UserDetails user = null;
try {
user = loadUserByUsername(username);
} catch (UsernameNotFoundException exception) {
throw new BadCredentialsException("invalid login details");
}
return createSuccessfulAuthentication(authentication, user);
}
private Authentication createSuccessfulAuthentication(final Authentication authentication, final UserDetails user) {
User dbUser = userRepository.findByUsername(user.getUsername());
UserRole userRole = userRoleRepository.findById(dbUser.getRoleId());
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(userRole.getName()));
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), authentication.getCredentials(), authorities);
token.setDetails(authentication.getDetails());
return token;
}
@Override
public boolean supports(Class < ? > authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
}
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserAuthenticationProvider userAuthenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.authenticationProvider(userAuthenticationProvider);
return http.build();
}
}