До безопасности я построил все, что есть (для пользователей):
Контроллер:
Код: Выделить всё
package de.ExpenseTracker.controller;
import de.ExpenseTracker.dto.RegisterUserData;
import de.ExpenseTracker.dto.ResponseData;
import de.ExpenseTracker.dto.LoginUserData;
import de.ExpenseTracker.service.UserService;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Locale;
@RestController
@RequestMapping("/users")
@AllArgsConstructor
public class UserController {
private final UserService userService;
private final MessageSource messageSource;
/**
* Registers a new user
*
* @param registerUserData DTO containing username, password and password confirmation
* @return ResponseData with username and message key
*/
@PostMapping("/register")
public ResponseData register(@Valid @RequestBody RegisterUserData registerUserData) {
userService.register(registerUserData);
return ResponseData.builder()
.messageKey(messageSource.getMessage("USER.CREATED", null, getLocale()))
.username(registerUserData.getUsername())
.build();
}
/**
* Logs in an existing user
*
* @param loginUserData DTO containing username and password
* @return ResponseData with message key
*/
@PostMapping("/login")
public ResponseData login(@Valid @RequestBody LoginUserData loginUserData) {
userService.login(loginUserData);
return ResponseData.builder()
.messageKey(messageSource.getMessage("USER.LOGGED_IN", null, getLocale()))
.build();
}
private Locale getLocale() {
return LocaleContextHolder.getLocale();
}
}
Код: Выделить всё
package de.ExpenseTracker.service;
import de.ExpenseTracker.dto.LoginUserData;
import de.ExpenseTracker.dto.RegisterUserData;
import de.ExpenseTracker.exceptions.ErrorCode;
import de.ExpenseTracker.exceptions.InvalidCredentialsException;
import de.ExpenseTracker.exceptions.UserNotFoundException;
import de.ExpenseTracker.model.Users;
import de.ExpenseTracker.repository.UserRepository;
import de.ExpenseTracker.exceptions.UserAlreadyExistsException;
import lombok.AllArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.time.Instant;
import java.util.UUID;
@Service
@AllArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
/**
* Registers a new User
*
* @param registerUserData the DTO that is given with user credentials
* @return The created Users entity
* @throws UserAlreadyExistsException if the username with the given username already exists
* @throws InvalidCredentialsException if the password and confirmation do not match
*
*/
public Users register(RegisterUserData registerUserData) throws UserAlreadyExistsException {
if (checkUserExist(registerUserData.getUsername())) {
throw new UserAlreadyExistsException(ErrorCode.USER_EXISTS);
}
if (!registerUserData.getPassword().equals(registerUserData.getPasswordConfirm())) {
throw new InvalidCredentialsException(ErrorCode.PASSWORD_MISMATCH);
}
Users user = Users.builder()
.userid(UUID.randomUUID())
.username(registerUserData.getUsername())
.passwordHash(passwordEncoder.encode(registerUserData.getPassword()))
.createdAt(Instant.now())
.build();
return userRepository.save(user);
}
/**
* Checks user Credentials for login and updates it if login is successful
*
* @param userData DTO containing username and password
* @return true if login is successful
* @throws UserNotFoundException if the username does not exist
* @throws InvalidCredentialsException if the password is incorrect
*/
public boolean login(LoginUserData userData) {
Users user = userRepository.findByUsername(userData.getUsername())
.orElseThrow(() -> new UserNotFoundException(ErrorCode.USER_NOT_FOUND));
boolean valid = passwordEncoder.matches(userData.getPassword(), user.getPasswordHash());
if (!valid) {
throw new InvalidCredentialsException(ErrorCode.PASSWORD_INCORRECT);
}
user.setLastLogin(Instant.now());
userRepository.save(user);
return true;
}
/**
* Retrieves a User entity from the database by its UUID
*
* @param userId The ID of the user to fetch
* @return the User entity
* @throws UserNotFoundException if no user with the given ID is found
*/
public Users getUserByIdOrThrow(UUID userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException(ErrorCode.USER_NOT_FOUND));
}
private boolean checkUserExist(String username) {
return userRepository.existsByUsername(username);
}
}
Код: Выделить всё
package de.ExpenseTracker.config.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/users/register").authenticated()
.anyRequest().permitAll());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Я надеюсь, что вопрос не слишком широк. написано.
Если вы предоставите хорошие ресурсы, где я смогу посмотреть, как это работает, это будет здорово.
Заранее спасибо!
Подробнее здесь: https://stackoverflow.com/questions/798 ... elp-needed
Мобильная версия