feat: add admin role and allow admins to create new users

This commit is contained in:
sBubshait 2025-07-21 08:49:02 +03:00
parent 00fe49b109
commit 930e6e5284
6 changed files with 104 additions and 1 deletions

View File

@ -68,6 +68,7 @@ public class SecurityConfig {
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.authenticationProvider(authenticationProvider())

View File

@ -3,6 +3,7 @@ package online.wesal.wesal.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import online.wesal.wesal.dto.CreateUserRequest;
import online.wesal.wesal.dto.LoginRequest;
import online.wesal.wesal.dto.LoginResponse;
import online.wesal.wesal.dto.UsernameSelectionRequest;
@ -65,4 +66,15 @@ public class AuthController {
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()));
}
}
}

View File

@ -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;
}
}

View File

@ -37,6 +37,9 @@ public class User {
@Column(nullable = false)
private boolean activated = false;
@Column(nullable = false)
private String role = "USER";
public User() {}
public User(String email, String password, String displayName) {
@ -108,4 +111,12 @@ public class User {
public void setActivated(boolean activated) {
this.activated = activated;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}

View File

@ -3,12 +3,15 @@ package online.wesal.wesal.service;
import online.wesal.wesal.entity.User;
import online.wesal.wesal.repository.UserRepository;
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.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@ -21,10 +24,13 @@ public class UserDetailsServiceImpl implements UserDetailsService {
User user = userRepository.findByEmail(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(
user.getEmail(),
user.getPassword(),
new ArrayList<>()
authorities
);
}
}

View File

@ -5,6 +5,7 @@ import online.wesal.wesal.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
@Service
@ -13,6 +14,9 @@ public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public User getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String email = authentication.getName();
@ -33,4 +37,22 @@ public class UserService {
user.setUsername(username);
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);
}
}