spring boot security 自定义AuthenticationProvider
spring boot security 自定义AuthenticationProvider
基于 spring boot 3.x
场景实现 手机验证码登陆
实现
CaptureCodeAuthenticationFilter
public class CaptureCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_LOGIN_URL = "/capture/login";
private static final String DEFAULT_PHONE_NAME = "phone";
private static final String DEFAULT_CODE_NAME = "code";
private String codeParamName = DEFAULT_CODE_NAME;
private String phoneParamName = DEFAULT_PHONE_NAME;
public CaptureCodeAuthenticationFilter(AuthenticationManager authenticationManager) {
super(DEFAULT_LOGIN_URL, authenticationManager);
}
public CaptureCodeAuthenticationFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {
super(defaultFilterProcessesUrl, authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String phone = obtainPhone(request);
phone = (phone != null) ? phone.trim() : "";
String code = obtainCaptureCode(request);
code = (code != null) ? code : "";
CaptureCodeAuthenticationToken token = new CaptureCodeAuthenticationToken(phone, code);
return this.getAuthenticationManager().authenticate(token);
}
protected String obtainCaptureCode(HttpServletRequest request) {
return request.getParameter(this.codeParamName);
}
protected String obtainPhone(HttpServletRequest request) {
return request.getParameter(this.phoneParamName);
}
}
CaptureCodeAuthenticationToken
public class CaptureCodeAuthenticationToken extends UsernamePasswordAuthenticationToken {
public CaptureCodeAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
}
CaptureCodeAuthenticationProvider
public class CaptureCodeAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
@Override
public boolean supports(Class<?> authentication) {
return (CaptureCodeAuthenticationToken.class.isAssignableFrom(authentication));
}
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
if (authentication.getPrincipal()==null){
throw new BadCredentialsException("Bad credentials "+ authentication.getPrincipal().toString());
}
if (authentication.getCredentials()==null){
throw new BadCredentialsException("Bad credentials "+ authentication.getPrincipal().toString());
}
}
@Override
protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
CaptureCodeAuthenticationToken token = (CaptureCodeAuthenticationToken) authentication;
if (!token.getPrincipal().equals("tom")){
throw new UsernameNotFoundException("username not fund!");
}
UserDetails user = User.withUsername("tom")
.password("tom")
.build();
return user;
}
}
配置 DefaultSecurityConfig
@Configuration
@EnableWebSecurity
public class DefaultSecurityConfig {
@Autowired
private ObjectMapper objectMapper;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(request -> request.anyRequest().authenticated());
http.formLogin(Customizer.withDefaults());
http.csrf(AbstractHttpConfigurer::disable);
http.addFilterBefore(captureCodeAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
public CaptureCodeAuthenticationFilter captureCodeAuthenticationFilter() {
ProviderManager providerManager = new ProviderManager(new CaptureCodeAuthenticationProvider());
CaptureCodeAuthenticationFilter filter =
new CaptureCodeAuthenticationFilter(providerManager);
filter.setAuthenticationSuccessHandler((request, response, authentication) -> {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(Result.ok("认证成功")));
response.getWriter().flush();
});
filter.setAuthenticationFailureHandler((request, response, exception) -> {
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(Result.ok("认证失败")));
response.getWriter().flush();
});
return filter;
}
@Bean
public UserDetailsService users(PasswordEncoder passwordEncoder) {
UserDetails user = User.withUsername("admin")
.password(passwordEncoder.encode("admin"))
.build();
return new InMemoryUserDetailsManager(user);
}
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}