Spring security, авторизация и регистрация пользователя
Пытаюсь реализовать регистрацию и авторизацию пользователей, используя spring security вместе со spring boot. Вроде делаю все по инструкции, однако есть пара ошибок: при переходе на страницу /register и вводе логина и пароля будущего пользователя, не происходит редиректа на /main, хотя в контроллере я явно указал
return "redirect:/main";
Кроме того, пользователя перебрасывает на /login, не понимаю почему, ведь /main страниуа, которая доступна всем пользователям. Ещё есть момент, что после ввода логина и пароля я вывожу их в консоль, там они корректно отображаются, но как только дело доходит до метода
userService.saveUser(user)
То не появляется новой записи в БД. Я пытался отследить, ест ли какая то ошибка при вызове метода простым условием, но такое ощущение, что метод просто не вызывается (при попытке отловить true или false ничего не происходит).
Прошу, не ругайте сильно, я пытаюсь разобраться с материалом сам, но иногда проскакивают моменты, где я совсем не понимаю, почему ничего не работает.
Код: MvcConfig.java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
WebSecurityConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Autowired
private UserRepository userRepository;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.anyRequest()
.permitAll()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
.defaultSuccessUrl("/main")
)
.logout((logout) -> logout.permitAll());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new UserService(userRepository, bCryptPasswordEncoder());
}
@Bean
public DaoAuthenticationProvider authenticationManager() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setPasswordEncoder(bCryptPasswordEncoder());
authProvider.setUserDetailsService(userDetailsService());
return authProvider;
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
MainPageController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/main")
public class MainPageController {
@GetMapping
public String showMainPage() {
return "main";
}
}
RegistrationController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
@RequestMapping("/register")
public class RegistrationController {
private UserService userService;
@Autowired
public RegistrationController(UserService userService) {
this.userService = userService;
}
@GetMapping
public String showRegPage() {
return "register";
}
@PostMapping
public String registerUser(@RequestParam (required = true, defaultValue = "!@") String username,
@RequestParam (required = true, defaultValue = "!@") String password) {
if(!(username.equals("!@") & password.equals("!@"))) {
System.out.println(username + " " + password);
User user = new User();
user.setUsername(username);
user.setPassword(password);
if(userService.saveUser(user))
System.out.println("GOOD");
else
System.out.println("BAD");
}
return "redirect:/main";
}
}
User.java (Entity)
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
@Entity
@Data
@NoArgsConstructor
@Table(name = "t_users")
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String role;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role);
return List.of(grantedAuthority);
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
UserRepository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username) throws UsernameNotFoundException;
}
UserService.java
import org.springframework.beans.factory.annotation.Autowired;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
@Service
public class UserService implements UserDetailsService {
private UserRepository userRepository;
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
public UserService(UserRepository userRepository,
BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userRepository = userRepository;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user == null) {
throw new UsernameNotFoundException("Cant find user with username: " + username);
}
return user;
}
public boolean saveUser(User user) {
if(loadUserByUsername(user.getUsername()) != null) {
return false;
}
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setRole("ROLE_USER");
userRepository.save(user);
System.out.println("SAVE USER METHOD");
return true;
}
public boolean deleteUser(Long userId) {
if (userRepository.findById(userId).isPresent()) {
userRepository.deleteById(userId);
return true;
}
return false;
}
}
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<title>Authorization</title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<h1>Login page</h1>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
main.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity6">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web Catalog</title>
</head>
<body>
<h1>Main Page</h1>
<h1 th:inline="text">Hello <span th:remove="tag" sec:authentication="name">USERNAME</span>!</h1>
<p>Click <a th:href="@{/login}">here</a> for login.</p>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
register.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<title>Registration</title>
</head>
<body>
<div th:if="${param.error}">
Some strange errors!
</div>
<h1>Registration page</h1>
<form th:action="@{/register}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/Database
spring.datasource.password=
spring.datasource.username=
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database=postgresql
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=true
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
Ответы (1 шт):
Как оказалось, ошибка была в методе saveUser, причем довольно глупая. Его следует переписать вот так:
public boolean saveUser(User user) {
User userFromDB = userRepository.findByUsername(user.getUsername());
if (userFromDB != null) {
return false;
}
user.setRole("ROLE_USER");
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRepository.save(user);
return true;
}