将用户名认证改为邮箱后无法登录——Spring Boot3与Spring Security6问题
Spring Boot 3 + Spring Security 6 邮箱登录验证失败问题
我有一个基于Spring Boot 3和Spring Security 6的项目,原本使用用户名认证可正常登录,但将认证方式改为邮箱后无法完成身份验证。
已完成的修改:
- 在SecurityConfig中添加
.usernameParameter("email"); - 将UserRepository中的
findByUsername()改为findByEmail(); - 将CustomUserDetails的
getUsername()方法中.getName()改为.getEmail(); - 将CustomUserDetailsService的
loadUserByUsername()中.findByName()改为.findByEmail()。
同时重构了基于Bootstrap的登录页面,怀疑问题可能出在登录页面或控制器中,以下是相关代码实现:
SecurityConfig
@Configuration @EnableWebSecurity public class SecurityConfig { private final UserDetailsService customUserDetailsService; private final SuccessUserHandler successUserHandler; @Autowired public SecurityConfig(UserDetailsService customUserDetailsService, SuccessUserHandler successUserHandler) { this.customUserDetailsService = customUserDetailsService; this.successUserHandler = successUserHandler; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) .authorizeHttpRequests((auth) -> auth .requestMatchers("/auth/login", "/auth/registration", "/error").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().hasAnyRole("USER", "ADMIN") ) .formLogin((login) -> login .loginPage("/auth/login") .loginProcessingUrl("/process_login") .usernameParameter("email") .successHandler(successUserHandler) .failureUrl("/auth/login?error") ) .logout(logout -> logout .logoutSuccessUrl("/auth/login") .permitAll() ); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setPasswordEncoder(passwordEncoder()); provider.setUserDetailsService(customUserDetailsService); return provider; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().requestMatchers("/resouces/**","/static/**","/css/**"); } }
User Model
@Entity @Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = {"user_id", "role_id"})) public class User { @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") private String name; @Column(name = "surname") private String surname; @Column(name = "birthYear") private int birthYear; @Column(name = "password") private String password; @Column(name = "email", unique = true) private String email; @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable( name = "users_roles", joinColumns = @JoinColumn( name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn( name = "role_id", referencedColumnName = "id")) private Collection<Role> roles; public User(String name, String surname, int birthYear) { this.name = name; this.surname = surname; this.birthYear = birthYear; } public User() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public int getBirthYear() { return birthYear; } public void setBirthYear(int birthYear) { this.birthYear = birthYear; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Collection<Role> getRoles() { return roles; } public void setRoles(Collection<Role> roles) { this.roles = roles; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", surname='" + surname + '\'' + ", birthYear=" + birthYear + '}'; } }
UserDetails
package task312.demo.securities; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import task312.demo.models.User; import java.util.Collection; import java.util.stream.Collectors; public class CustomUserDetails implements UserDetails { private User user; public CustomUserDetails(User user) { this.user = user; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return user.getRoles().stream() .map(role -> new SimpleGrantedAuthority(role.getName())) .collect(Collectors.toList()); } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return user.getEmail(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public User getUser() { return this.user; } }
UserDetailsService
@Service public class CustomUserDetailsService implements UserDetailsService { private final UserRepository userRepository; @Autowired public CustomUserDetailsService(UserRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional<User> user = userRepository.findByEmail(email); if (user.isEmpty()) { throw new UsernameNotFoundException("User not found"); } return new CustomUserDetails(user.get()); } }
UserRepository
@Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByEmail(String email); }
UserService
@Service @Transactional(readOnly = true) public class UserServiceImpl implements UserService { private final UserRepository userRepository; @Autowired public UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; } @Override public List<User> findAll() { return userRepository.findAll(); } @Override public User findById(Long id) { Optional<User> foundUser = userRepository.findById(id); return foundUser.orElseThrow(EntityNotFoundException::new); } @Override @Transactional public void save(User user) { userRepository.save(user); } @Override @Transactional public void update(Long id, User updatedUser) { updatedUser.setId(id); userRepository.save(updatedUser); } @Override @Transactional public void delete(Long id) { Optional<User> userToDelete = userRepository.findById(id); // userToDelete.ifPresent(user -> user.getRoles().clear()); userRepository.deleteById(id); } @Override @Transactional public void deleteAll() { userRepository.deleteAll(); } @Override public User findByUsername(String username) { Optional<User> user = userRepository.findByEmail(username); if (user.isPresent()) { return user.get(); } else { throw new UsernameNotFoundException(username); } } @Override public User findByEmail(String email) { Optional<User> user = userRepository.findByEmail(email); if (user.isPresent()) { return user.get(); } else { throw new UsernameNotFoundException(email); } } @Override public boolean isUserAdmin(String username) { Optional<User> user = userRepository.findByEmail(username); if (user.isPresent()) { return user.get().getRoles().stream().anyMatch(role -> "ROLE_ADMIN".equals(role.getName())); } else { return false; } } }
SuccessHandler
@Component public class SuccessUserHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException { Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities()); if (roles.contains("ROLE_ADMIN")) { httpServletResponse.sendRedirect("/admin"); } else { httpServletResponse.sendRedirect("/user"); } } }
Login page
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" xmlns:th="http://www.thymeleaf.org"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap demo</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> <link rel="stylesheet" th:href="@{/css/login.css}"/> </head> <body class="bg-light"> <div class="container"> <div class="justify-content-center"> <div class="info"> <h3>Please sign in</h3> </div> <form th:action="@{/process_login}" method="post"> <div class="col-3 mx-auto "> <div class="mb-1"> <input type="email" class="form-control" id="email" name="email" placeholder="Email"> </div> <div class="mb-3"> <input type="password" id="inputPassword6" class="form-control" aria-describedby="passwordHelpInline" placeholder="Password"> </div> <div class="mx-auto"> <button type="submit" class="btn btn-primary w-100 text-center">Sign in</button> </div> </div> </form> <div th:if="${param.error}" class="text-center mt-3" style="color: red">Wrong username or password</div> <div class="col-3 mx-auto text-center mt-3"> <a th:href="@{/auth/registration}" class="link-underline link-underline-opacity-0">Registration</a> <div/> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> </body> </html>
AuthController
@Controller @RequestMapping("/auth") public class AuthController { private final RegistrationService registrationService; @Autowired public AuthController(RegistrationService registrationService) { this.registrationService = registrationService; } @GetMapping("/login") public String getLoginPage() { return "auth/login"; } @GetMapping("/registration") public String getRegistrationPage(@ModelAttribute("user") User user) { return "auth/registration"; } @PostMapping("/registration") public String doRegistration(@ModelAttribute("user") User user) { try { registrationService.register(user); } catch (Exception e) { e.printStackTrace(); return "auth/registration"; } return "redirect:/auth/login"; } }
内容的提问来源于stack exchange,提问作者savemysoul
相关产品推荐
相关产品推荐

