поменяла классы для юзера, добавила дто для регистрации, обновила сервис (для проверки юзернейма (логина блин, юзернейма аааааааааа))

This commit is contained in:
Елена Бакальская 2024-05-11 19:14:54 +04:00
parent 2173e08c60
commit 6f5fe27b71
8 changed files with 290 additions and 14 deletions

Binary file not shown.

View File

@ -0,0 +1,63 @@
package com.example.backend.core.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import com.example.backend.core.configurations.Constants;
import com.example.backend.users.api.UserSignupController;
import com.example.backend.users.model.UserRole;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin));
httpSecurity.csrf(AbstractHttpConfigurer::disable);
httpSecurity.cors(Customizer.withDefaults());
httpSecurity.authorizeHttpRequests(requests -> requests
.requestMatchers("/css/**", "/webjars/**", "/*.svg")
.permitAll());
httpSecurity.authorizeHttpRequests(requests -> requests
.requestMatchers(Constants.ADMIN_PREFIX + "/**").hasRole(UserRole.ADMIN.name())
.requestMatchers("/h2-console/**").hasRole(UserRole.ADMIN.name())
.requestMatchers(UserSignupController.URL).anonymous()
.requestMatchers(Constants.LOGIN_URL).anonymous()
.anyRequest().authenticated());
httpSecurity.formLogin(formLogin -> formLogin
.loginPage(Constants.LOGIN_URL));
httpSecurity.rememberMe(rememberMe -> rememberMe.key("uniqueAndSecret"));
httpSecurity.logout(logout -> logout
.deleteCookies("JSESSIONID"));
return httpSecurity.build();
}
@Bean
DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@ -0,0 +1,64 @@
package com.example.backend.core.security;
import java.util.Collection;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.backend.users.model.UserEntity;
public class UserPrincipal implements UserDetails {
private final long id;
private final String username;
private final String password;
private final Set<? extends GrantedAuthority> roles;
private final boolean active;
public UserPrincipal(UserEntity user) {
this.id = user.getId();
this.username = user.getLogin();
this.password = user.getPassword();
this.roles = Set.of(user.getRole());
this.active = true;
}
public Long getId() {
return id;
}
@Override
public String getUsername() {
return username;
}
@Override
public String getPassword() {
return password;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles;
}
@Override
public boolean isEnabled() {
return active;
}
@Override
public boolean isAccountNonExpired() {
return isEnabled();
}
@Override
public boolean isAccountNonLocked() {
return isEnabled();
}
@Override
public boolean isCredentialsNonExpired() {
return isEnabled();
}
}

View File

@ -0,0 +1,65 @@
package com.example.backend.users.api;
import java.util.Objects;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.backend.core.configurations.Constants;
import com.example.backend.users.model.UserEntity;
import com.example.backend.users.service.UserService;
import jakarta.validation.Valid;
@Controller
@RequestMapping(UserSignupController.URL)
public class UserSignupController {
public static final String URL = "/signup";
private static final String SIGNUP_VIEW = "signup";
private static final String USER_ATTRIBUTE = "user";
private final UserService userService;
private final ModelMapper modelMapper;
public UserSignupController(
UserService userService,
ModelMapper modelMapper) {
this.userService = userService;
this.modelMapper = modelMapper;
}
private UserEntity toEntity(UserSignupDTO dto) {
return modelMapper.map(dto, UserEntity.class);
}
@GetMapping
public String getSignup(Model model) {
model.addAttribute(USER_ATTRIBUTE, new UserSignupDTO());
return SIGNUP_VIEW;
}
@PostMapping
public String signup(
@ModelAttribute(name = USER_ATTRIBUTE) @Valid UserSignupDTO user,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
return SIGNUP_VIEW;
}
if (!Objects.equals(user.getPassword(), user.getPasswordConfirm())) {
bindingResult.rejectValue("password", "signup:passwords", "Пароли не совпадают.");
model.addAttribute(USER_ATTRIBUTE, user);
return SIGNUP_VIEW;
}
userService.create(toEntity(user));
return Constants.REDIRECT_VIEW + Constants.LOGIN_URL + "?signup";
}
}

View File

@ -0,0 +1,40 @@
package com.example.backend.users.api;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class UserSignupDTO {
@NotBlank
@Size(min = 3, max = 20)
private String login;
@NotBlank
@Size(min = 3, max = 20)
private String password;
@NotBlank
@Size(min = 3, max = 20)
private String passwordConfirm;
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirm() {
return passwordConfirm;
}
public void setPasswordConfirm(String passwordConfirm) {
this.passwordConfirm = passwordConfirm;
}
}

View File

@ -13,7 +13,7 @@ import jakarta.persistence.Table;
public class UserEntity extends BaseEntity {
@Column(nullable = false, unique = true, length = 15)
private String username;
private String login;
@Column(nullable = false, length = 5)
private String password;
@ -24,18 +24,18 @@ public class UserEntity extends BaseEntity {
}
public UserEntity(Integer id, String username, String password) {
this.username = username;
public UserEntity(Integer id, String login, String password) {
this.login = login;
this.password = password;
this.role = UserRole.USER;
}
public String getUsername() {
return username;
public String getLogin() {
return login;
}
public void setUsername(String username) {
this.username = username;
public void setLogin(String login) {
this.login = login;
}
public String getPassword() {
@ -56,7 +56,7 @@ public class UserEntity extends BaseEntity {
@Override
public int hashCode() {
return Objects.hash(id, username, password, role);
return Objects.hash(id, login, password, role);
}
@Override
@ -67,7 +67,7 @@ public class UserEntity extends BaseEntity {
return false;
final UserEntity other = (UserEntity) obj;
return Objects.equals(other.getId(), id) &&
Objects.equals(other.getUsername(), username) &&
Objects.equals(other.getLogin(), login) &&
Objects.equals(other.getRole(), role) &&
Objects.equals(other.getPassword(), password);
}

View File

@ -7,4 +7,6 @@ import com.example.backend.users.model.UserEntity;
public interface UserRepository extends CrudRepository<UserEntity, Integer> {
Optional<UserEntity> findByUsernameIgnoreCase(String username);
Optional<UserEntity> findByLoginIgnoreCase(String login);
}

View File

@ -1,22 +1,41 @@
package com.example.backend.users.service;
import java.util.List;
import java.util.Optional;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.stream.StreamSupport;
import com.example.backend.core.configurations.Constants;
import com.example.backend.core.errors.NotFoundException;
import com.example.backend.core.security.UserPrincipal;
import com.example.backend.users.model.UserEntity;
import com.example.backend.users.model.UserRole;
import com.example.backend.users.repository.UserRepository;
@Service
public class UserService {
public class UserService implements UserDetailsService {
private final UserRepository repository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository repository) {
public UserService(UserRepository repository, PasswordEncoder passwordEncoder) {
this.repository = repository;
this.passwordEncoder = passwordEncoder;
}
private void checkLogin(Integer id, String login) {
final Optional<UserEntity> existsUser = repository.findByLoginIgnoreCase(login);
if (existsUser.isPresent() && !existsUser.get().getId().equals(id)) {
throw new IllegalArgumentException(
String.format("User with login %s is already exists", login));
}
}
@Transactional(readOnly = true)
@ -29,18 +48,35 @@ public class UserService {
return repository.findById(id).orElseThrow(() -> new NotFoundException(id));
}
@Transactional(readOnly = true)
private UserEntity getByLogin(String username) {
return repository.findByLoginIgnoreCase(username)
.orElseThrow(() -> new IllegalArgumentException("Такого логина нет... хде вы его взяли?"));
}
@Transactional
public UserEntity create(UserEntity entity) {
if (entity == null) {
throw new IllegalArgumentException("Entity is null");
}
checkLogin(null, entity.getLogin());
final String password = Optional.ofNullable(entity.getPassword()).orElse("");
entity.setPassword(
passwordEncoder.encode(StringUtils.hasText(password.strip()) ? password : Constants.DEFAULT_PASSWORD));
entity.setRole(Optional.ofNullable(entity.getRole()).orElse(UserRole.USER));
repository.save(entity);
return repository.save(entity);
}
@Transactional
public UserEntity update(Integer id, UserEntity entity) {
final UserEntity existsentity = get(id);
existsentity.setUsername(entity.getUsername());
checkLogin(id, entity.getLogin());
existsentity.setLogin(entity.getLogin());
existsentity.setPassword(entity.getPassword());
existsentity.setIsAdmin(entity.getIsAdmin());
return repository.save(existsentity);
existsentity.setRole(entity.getRole());
repository.save(existsentity);
return existsentity;
}
@Transactional
@ -50,4 +86,10 @@ public class UserService {
return existsentity;
}
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final UserEntity existUser = getByLogin(username);
return new UserPrincipal(existUser);
}
}