Careeroza
Loading Roles from the Database
User and Role Tables
In ShopEase the roles live in the database. A user can have several roles (for example a seller who also shops). The entity mapping is covered in the Hibernate & JPA material; here we only need the result.
@Entity
@Table(name = "users")
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String email;
private String passwordHash;
private boolean enabled = true;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "user_roles", joinColumns = @JoinColumn(name = "user_id"))
@Enumerated(EnumType.STRING)
@Column(name = "role")
private Set<Role> roles = new HashSet<>();
// getters...
}
public enum Role { CUSTOMER, SELLER, ADMIN }UserDetailsService with Roles
@Service
public class ShopUserDetailsService implements UserDetailsService {
private final UserRepository users;
public ShopUserDetailsService(UserRepository users) {
this.users = users;
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User u = users.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("No user " + email));
List<GrantedAuthority> authorities = u.getRoles().stream()
.map(r -> (GrantedAuthority) new SimpleGrantedAuthority("ROLE_" + r.name()))
.toList();
return org.springframework.security.core.userdetails.User.withUsername(u.getEmail())
.password(u.getPasswordHash())
.authorities(authorities)
.disabled(!u.isEnabled())
.build();
}
}Reading the Current User's Authorities
@GetMapping("/api/me")
public Map<String, Object> me(Authentication authentication) {
return Map.of(
"email", authentication.getName(),
"authorities", authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).sorted().toList());
}Example
curl -u [email protected]:ravi123 localhost:8080/api/meExample output
HTTP/1.1 200 OK
{"email":"[email protected]","authorities":["ROLE_CUSTOMER","ROLE_SELLER"]}Exercise
Exercise: Write URL rules so that: GET /api/reports/** needs the authority report:read, POST /api/coupons needs role ADMIN, and everything under /api/cart/** needs any logged-in user.
Show answer
http.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.GET, "/api/reports/**").hasAuthority("report:read")
.requestMatchers(HttpMethod.POST, "/api/coupons").hasRole("ADMIN")
.requestMatchers("/api/cart/**").authenticated()
.anyRequest().authenticated());