Step 1: 创建自定义UserDetails类
自定义一个实现UserDetails接口的类,用于表示用户信息。您可以在这个类中添加自己需要的属性和方法来存储用户信息。
public class CustomUserDetails implements UserDetails {private String email;private boolean enabled;private List<GrantedAuthority> authorities;public CustomUserDetails(String email, boolean enabled, List<GrantedAuthority> authorities) {this.email = email;this.enabled = enabled;this.authorities = authorities;}// Implement other UserDetails methods...@Overridepublic String getUsername() {return email;}// Getters and setters...
}
Step 2: 创建自定义过滤器
创建一个自定义的过滤器,用于处理邮箱验证码登录逻辑。这个过滤器将在用户登录时验证邮箱和验证码,并完成用户认证过程。
public class EmailVerificationAuthenticationFilter extends AbstractAuthenticationProcessingFilter {public EmailVerificationAuthenticationFilter() {super(new AntPathRequestMatcher("/login/email", "POST"));}@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)throws AuthenticationException {String email = obtainEmail(request);String verificationCode = obtainVerificationCode(request);email = (email != null) ? email.trim() : "";verificationCode = (verificationCode != null) ? verificationCode.trim() : "";EmailVerificationToken authRequest = new EmailVerificationToken(email, verificationCode);return this.getAuthenticationManager().authenticate(authRequest);}private String obtainEmail(HttpServletRequest request) {return request.getParameter("email");}private String obtainVerificationCode(HttpServletRequest request) {return request.getParameter("verificationCode");}
}
Step 3: 创建自定义认证令牌
创建一个自定义的认证令牌,继承自UsernamePasswordAuthenticationToken,用于封装用户的邮箱和验证码信息。
public class EmailVerificationToken extends UsernamePasswordAuthenticationToken {private final String email;private final String verificationCode;public EmailVerificationToken(String email, String verificationCode) {super(email, verificationCode);this.email = email;this.verificationCode = verificationCode;}public String getEmail() {return email;}public String getVerificationCode() {return verificationCode;}
}
Step 4: 实现自定义AuthenticationProvider
创建一个自定义的AuthenticationProvider,用于处理邮箱验证登录的认证逻辑。
@Component
public class EmailVerificationAuthenticationProvider implements AuthenticationProvider {@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {String email = authentication.getName();String verificationCode = authentication.getCredentials().toString();// 在此处编写您的自定义认证逻辑// 比如根据email和verificationCode验证用户信息if (authenticationIsValid) {List<GrantedAuthority> authorities = new ArrayList<>();authorities.add(new SimpleGrantedAuthority("ROLE_USER"));CustomUserDetails userDetails = new CustomUserDetails(email, true, authorities);return new UsernamePasswordAuthenticationToken(userDetails, null, authorities);} else {throw new AuthenticationServiceException("Authentication failed");}}@Overridepublic boolean supports(Class<?> authentication) {return EmailVerificationToken.class.isAssignableFrom(authentication);}
}
Step 5: 实现自定义UserDetailsService
创建一个实现UserDetailsService接口的类,用于根据邮箱查询用户信息。
@Service
public class CustomUserDetailsService implements UserDetailsService {private final UserRepository userRepository;@Autowiredpublic CustomUserDetailsService(UserRepository userRepository) {this.userRepository = userRepository;}@Overridepublic UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {// 在此处实现根据邮箱查询用户信息的逻辑CustomUser user = userRepository.findByEmail(email);if (user == null) {throw new UsernameNotFoundException("User not found with email: " + email);}List<GrantedAuthority> authorities = new ArrayList<>();authorities.add(new SimpleGrantedAuthority("ROLE_USER"));return new CustomUserDetails(user.getEmail(), user.isEnabled(), authorities);}
}
Step 6: 配置Spring Security
在Spring Security配置类中配置自定义过滤器、认证提供者和UserDetailsService。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final EmailVerificationAuthenticationProvider emailVerificationAuthenticationProvider;private final CustomUserDetailsService customUserDetailsService;@Autowiredpublic SecurityConfig(EmailVerificationAuthenticationProvider emailVerificationAuthenticationProvider, CustomUserDetailsService customUserDetailsService) {this.emailVerificationAuthenticationProvider = emailVerificationAuthenticationProvider;this.customUserDetailsService = customUserDetailsService;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(emailVerificationAuthenticationProvider);auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.addFilterBefore(emailVerificationAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").defaultSuccessUrl("/dashboard").and().logout().logoutUrl("/logout").logoutSuccessUrl("/login");}@Beanpublic EmailVerificationAuthenticationFilter emailVerificationAuthenticationFilter() throws Exception {EmailVerificationAuthenticationFilter filter = new EmailVerificationAuthenticationFilter();filter.setAuthenticationManager(authenticationManagerBean());return filter;}@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance(); // For simplicity, use NoOpPasswordEncoder}
}