SpringBoot2.7.x版本中SpringSecurity账号和手机验证码登录多重认证实践
SecurityConfig配置
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig {
@Autowired
private AuthenticationEntryPointImpl authenticationEntryPoint;
@Autowired
private RestfulAccessDeniedHandler accessDeniedHandler;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private SmsAuthenticationProvider smsAuthenticationProvider;
/**
* 访问路径白名单
*/
private static final String[] WHITE_PATH = new String[] { "/login/xx", "/login", "/register/**",
"/send/sms/**", };
/**
* get方式访问路径白名单
*/
private static final String[] GET_WHITE_PATH = new String[] { "/user/list" };
private DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
daoAuthenticationProvider.setUserDetailsService(userDetailsService);
return daoAuthenticationProvider;
}
@Bean
public AuthenticationManager authenticationManager() throws Exception {
ProviderManager authenticationManager = new ProviderManager(
Arrays.asList(smsAuthenticationProvider, daoAuthenticationProvider()));
// 不擦除认证密码
authenticationManager.setEraseCredentialsAfterAuthentication(false);
return authenticationManager;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable().cors().and()
.logout().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
.authorizeRequests(authorize -> authorize
.antMatchers(WHITE_PATH).permitAll()
.antMatchers(HttpMethod.GET, GET_WHITE_PATH).permitAll()
.anyRequest().authenticated())
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
JWT认证过滤器
/**
* JWT认证过滤器
*
* @author admin
*
*/
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String token = request.getHeader(Constants.TOKEN_HEADER);
if (StrUtil.isEmpty(token) || !JwtTokenUtil.validateToken(token)) {
chain.doFilter(request, response);
return;
}
String username = JwtTokenUtil.getUsername(token);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
chain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
chain.doFilter(request, response);
}
}