自定义token,继承 AbstractAuthenticationToken
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
public class SmsAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 530L;
private final Object principal;
private Object credentials;
public SmsAuthenticationToken(Object principal, Object credentials) {
super((Collection) null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
public SmsAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
} else {
super.setAuthenticated(false);
}
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
自定义拦截类Filter,继承AbstractAuthenticationProcessingFilter
import com.base.web.config.security.authentication.SmsAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JwtSmsLoginFilter extends AbstractAuthenticationProcessingFilter {
public JwtSmsLoginFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
}
@Override
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String phoneNo = request.getParameter("phoneNo");
String code = request.getParameter("code");
if (phoneNo == null) {
phoneNo = "";
}
if (code == null) {
code = "";
}
SmsAuthenticationToken token = new SmsAuthenticationToken(phoneNo, code);
token.setDetails(this.authenticationDetailsSource.buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(token);
return super.getAuthenticationManager().authenticate(token);
}
}
实现登录验证逻辑
import cn.hutool.core.util.ObjectUtil;
import com.base.common.constant.WebConstant;
import com.base.redis.utils.RedisCacheUtil;
import com.base.web.config.security.authentication.SmsAuthenticationToken;
import com.base.web.service.AccountService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collection;
@Component
public class SmsAuthenticationProvider implements AuthenticationProvider {
@Resource
private AccountService accountService;
@Resource
private RedisCacheUtil redisCacheUtil;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String phoneNo = authentication.getName();
String code = (String) authentication.getCredentials();
if (StringUtils.isBlank(phoneNo)) {
throw new UsernameNotFoundException("手机号不可以为空");
}
if (StringUtils.isBlank(code)) {
throw new BadCredentialsException("验证码不可以为空");
}
String key = phoneNo + WebConstant.REDIS_KEY_SUFFIX_FOR_VERIFICATION_CODE;
boolean hasCode = redisCacheUtil.hasKey(key);
if (!hasCode) {
throw new BadCredentialsException("短信验证码已失效请重新获取");
}
String smsCode = redisCacheUtil.getString(key);
if (!smsCode.equalsIgnoreCase(code)) {
throw new BadCredentialsException("验证码错误");
}
redisCacheUtil.delete(key);
UserDetails user = accountService.loadUserByUsername(phoneNo);
if (ObjectUtil.isEmpty(user)) {
throw new BadCredentialsException("用户信息加载失败");
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, null, authorities);
}
@Override
public boolean supports(Class<?> aClass) {
return SmsAuthenticationToken.class.isAssignableFrom(aClass);
}
}
security配置
http.addFilterBefore(smsLoginFilter(), AbstractPreAuthenticatedProcessingFilter.class);
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService)
.passwordEncoder(passwordEncoder())
.and()
.authenticationProvider(smsAuthenticationProvider)
.authenticationProvider(passwordAuthenticationProvider);
}
@Bean
public AbstractAuthenticationProcessingFilter smsLoginFilter() throws Exception {
JwtSmsLoginFilter jwtSmsLoginFilter = new JwtSmsLoginFilter(new AntPathRequestMatcher("/account/login", "POST"));
jwtSmsLoginFilter.setAuthenticationManager(this.authenticationManager());
jwtSmsLoginFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
jwtSmsLoginFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
return jwtSmsLoginFilter;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」