feat: add admin role and allow admins to create new users
This commit is contained in:
parent
00fe49b109
commit
930e6e5284
@ -68,6 +68,7 @@ public class SecurityConfig {
|
|||||||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/", "/login", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
.requestMatchers("/", "/login", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
|
||||||
|
.requestMatchers("/admin/**").hasRole("ADMIN")
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.authenticationProvider(authenticationProvider())
|
.authenticationProvider(authenticationProvider())
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package online.wesal.wesal.controller;
|
|||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import online.wesal.wesal.dto.CreateUserRequest;
|
||||||
import online.wesal.wesal.dto.LoginRequest;
|
import online.wesal.wesal.dto.LoginRequest;
|
||||||
import online.wesal.wesal.dto.LoginResponse;
|
import online.wesal.wesal.dto.LoginResponse;
|
||||||
import online.wesal.wesal.dto.UsernameSelectionRequest;
|
import online.wesal.wesal.dto.UsernameSelectionRequest;
|
||||||
@ -65,4 +66,15 @@ public class AuthController {
|
|||||||
return ResponseEntity.badRequest().build();
|
return ResponseEntity.badRequest().build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/admin/createUser")
|
||||||
|
@Operation(summary = "Create new user (Admin only)", description = "Creates a new user - requires admin privileges")
|
||||||
|
public ResponseEntity<?> createUser(@Valid @RequestBody CreateUserRequest request) {
|
||||||
|
try {
|
||||||
|
User user = userService.createUser(request.getEmail(), request.getPassword(), request.getDisplayName());
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package online.wesal.wesal.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class CreateUserRequest {
|
||||||
|
|
||||||
|
@Email
|
||||||
|
@NotBlank
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 8)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
private String displayName;
|
||||||
|
|
||||||
|
public CreateUserRequest() {}
|
||||||
|
|
||||||
|
public CreateUserRequest(String email, String password, String displayName) {
|
||||||
|
this.email = email;
|
||||||
|
this.password = password;
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,9 @@ public class User {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private boolean activated = false;
|
private boolean activated = false;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String role = "USER";
|
||||||
|
|
||||||
public User() {}
|
public User() {}
|
||||||
|
|
||||||
public User(String email, String password, String displayName) {
|
public User(String email, String password, String displayName) {
|
||||||
@ -108,4 +111,12 @@ public class User {
|
|||||||
public void setActivated(boolean activated) {
|
public void setActivated(boolean activated) {
|
||||||
this.activated = activated;
|
this.activated = activated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRole(String role) {
|
||||||
|
this.role = role;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -3,12 +3,15 @@ package online.wesal.wesal.service;
|
|||||||
import online.wesal.wesal.entity.User;
|
import online.wesal.wesal.entity.User;
|
||||||
import online.wesal.wesal.repository.UserRepository;
|
import online.wesal.wesal.repository.UserRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||||
@ -21,10 +24,13 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
|||||||
User user = userRepository.findByEmail(email)
|
User user = userRepository.findByEmail(email)
|
||||||
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
||||||
|
|
||||||
|
Collection<GrantedAuthority> authorities = new ArrayList<>();
|
||||||
|
authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getRole()));
|
||||||
|
|
||||||
return new org.springframework.security.core.userdetails.User(
|
return new org.springframework.security.core.userdetails.User(
|
||||||
user.getEmail(),
|
user.getEmail(),
|
||||||
user.getPassword(),
|
user.getPassword(),
|
||||||
new ArrayList<>()
|
authorities
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,6 +5,7 @@ import online.wesal.wesal.repository.UserRepository;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@ -13,6 +14,9 @@ public class UserService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
public User getCurrentUser() {
|
public User getCurrentUser() {
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
String email = authentication.getName();
|
String email = authentication.getName();
|
||||||
@ -33,4 +37,22 @@ public class UserService {
|
|||||||
user.setUsername(username);
|
user.setUsername(username);
|
||||||
return userRepository.save(user);
|
return userRepository.save(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCurrentUserAdmin() {
|
||||||
|
User user = getCurrentUser();
|
||||||
|
return "ADMIN".equals(user.getRole());
|
||||||
|
}
|
||||||
|
|
||||||
|
public User createUser(String email, String password, String displayName) {
|
||||||
|
if (!isCurrentUserAdmin()) {
|
||||||
|
throw new RuntimeException("Access denied: Admin privileges required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userRepository.existsByEmail(email)) {
|
||||||
|
throw new RuntimeException("User with this email already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User(email, passwordEncoder.encode(password), displayName);
|
||||||
|
return userRepository.save(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user