I try to realise an authorization, but cannot get the cause of this problem: Encoded password does not look like BCrypt
My actions sequence: open localhost:8080/login
, write "user" in login input and "password" in password (user with such login and password is guaranteed to exist), submit, here the problem appears (Encoded password does not look like BCrypt
is written in console), login is failed.
I am new at Spring, so I need your experienced advice. I guess, the reason is in the auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
in protected void configure(AuthenticationManagerBuilder auth)
method in WebSecurityConfig.java
, but I cannot apply any solution I've found.
WebSecurityConfig.java
package com.todo.todo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import com.todo.todo.services.UserService;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig{
@Autowired
private UserService userService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.antMatchers("/",
"/index",
"/users",
"/registrate",
"/deleteuser/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout.permitAll());
return http.build();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserService.java
package com.todo.todo.services;
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.stereotype.Service;
import com.todo.todo.repositories.UserRepository;
@Service
public class UserService implements UserDetailsService{
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails userDetails = userRepository.findByUsername(username);
if(userDetails == null) throw new UsernameNotFoundException("No such username");
return userDetails;
}
}
UserRepository.java
package com.todo.todo.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import com.todo.todo.models.User;
public interface UserRepository extends JpaRepository<User, Long>{
User findByUsername(String username);
}
UserController.java
package com.todo.todo.controllers;
import java.time.Instant;
import java.util.Collections;
import java.util.Map;
import java.util.NoSuchElementException;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;
import com.todo.todo.models.Role;
import com.todo.todo.models.User;
import com.todo.todo.repositories.UserRepository;
@Controller
public class UserController {
private final String registratePage = "registrate";
// private final String loginPage = "login";
private final String redirectLoginPage = "redirect:/login";
private final String redirectUsersPage = "redirect:/users";
@Autowired
private UserRepository userRepository;
@GetMapping("/users")
public ModelAndView getHomePage(@AuthenticationPrincipal User user){
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("users");
modelAndView.addObject("users", userRepository.findAll());
return modelAndView;
}
@GetMapping("/deleteuser/{id}")
public String deleteTask(@PathVariable("id") Long id, Model model){
User user = userRepository.findById(id).orElseThrow(() -> new NoSuchElementException("User not found by id = " id));
userRepository.delete(user);
return redirectUsersPage;
}
@GetMapping("/registrate")
public String getRegistratePage(){
return registratePage;
}
@PostMapping("/registrate")
public String registrateUser(@Valid User user, Map<String, Object> map){
User userFromDatabase = userRepository.findByUsername(user.getUsername());
if(userFromDatabase != null){
map.put("message", "User has been already registrated!");
return registratePage;
}
user.setCreatedDate(Instant.now());
user.setRoles(Collections.singleton(Role.USER));
userRepository.save(user);
map.put("message", "User has been successfully registrated!");
return redirectLoginPage;
}
}
User.java
package com.todo.todo.models;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "usr")
public class User implements UserDetails{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@NotBlank(message = "Fill username")
private String username;
@NotBlank(message = "Fill password")
private String password;
private Instant createdDate;
@ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
@CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
@Enumerated(EnumType.STRING)
private Set<Role> roles;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
this.createdDate = Instant.now();
this.roles = new HashSet<>();
}
@Override
public String toString() {
return String.format("User{id=%d, username='%s', password='%s', createdDate='%s'}",
id, username, password, createdDate);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return getRoles();
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
login.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-springsecurity3">
<head>
<title>LOGIN</title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<span th:text="${message}"></span>
<form th:action="@{/login}" method="POST">
<div><label> Username : <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>
<a href="/registrate">Create new user</a>
<a href="/users">To users</a>
</body>
</html>
CodePudding user response:
I solved this
WebSecurityConfig.java
package com.todo.todo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import com.todo.todo.services.UserService;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.antMatchers("/",
"/index",
"/tasks",
"/users",
"/registrate",
"/logout",
"/deleteuser/**",
"/create",
"/delete/**",
"/update/**",
"/create_task",
"/update_task",
"/h2-console/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll()
)
.logout((logout) -> logout.permitAll());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
UserController.java Added encoding password in @PostMapping("/registrate")
// some imports here
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
// some methods here
@PostMapping("/registrate")
public String registrateUser(@Valid User user, Map<String, Object> map){
User userFromDatabase = userRepository.findByUsername(user.getUsername());
if(userFromDatabase != null){
map.put("message", "User has been already registrated!");
return registratePage;
}
String encodedPassword = new BCryptPasswordEncoder().encode(user.getPassword());
user.setPassword(encodedPassword);
user.setCreatedDate(Instant.now());
user.setRoles(Collections.singleton(Role.USER));
userRepository.save(user);
map.put("message", "User has been successfully registrated!");
return redirectLoginPage;
}