Spring Boot Security自定义AuthenticationProvider

以下是一个简单的示例,展示如何使用AuthenticationProvider自定义身份验证。首先,创建一个继承自标准AuthenticationProvider的类,并实现authenticate方法。

java 复制代码
import com.kamier.security.web.service.MyUser;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
import java.util.HashMap;
import java.util.Map;
 
public class MobilecodeAuthenticationProvider implements AuthenticationProvider {
 
    private UserDetailsService userDetailsService;
 
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
 
        MobilecodeAuthenticationToken mobilecodeAuthenticationToken = (MobilecodeAuthenticationToken) authentication;
        String phone = mobilecodeAuthenticationToken.getPhone();
        String mobileCode = mobilecodeAuthenticationToken.getMobileCode();
        System.out.println("登陆手机号:" + phone);
        System.out.println("手机验证码:" + mobileCode);
 
        // 模拟从redis中读取手机号对应的验证码及其用户名
        Map dataFromRedis = new HashMap();
        dataFromRedis.put("code", "6789");
        dataFromRedis.put("username", "admin");
 
        // 判断验证码是否一致
        if (!mobileCode.equals(dataFromRedis.get("code"))) {
            throw new BadCredentialsException("验证码错误");
        }
 
        // 如果验证码一致,从数据库中读取该手机号对应的用户信息
        MyUser loadedUser = (MyUser) userDetailsService.loadUserByUsername(dataFromRedis.get("username"));
        if (loadedUser == null) {
            throw new UsernameNotFoundException("用户不存在");
        } else {
            MobilecodeAuthenticationToken result = new MobilecodeAuthenticationToken(loadedUser, null, loadedUser.getAuthorities());
            return result;
        }
    }
 
    @Override
    public boolean supports(Class> aClass) {
        return MobilecodeAuthenticationToken.class.isAssignableFrom(aClass);
    }
 
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
}

注意这里的supports方法,是实现多种认证方式的关键,认证管理器AuthenticationManager会通过这个supports方法来判定当前需要使用哪一种认证方式

上面的就是只支持****MobilecodeAuthenticationToken

java 复制代码
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
 
/**
 * 手机验证码认证信息,在UsernamePasswordAuthenticationToken的基础上添加属性 手机号、验证码
 */
public class MobilecodeAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = 530L;
    private Object principal;
    private Object credentials;
    private String phone;
    private String mobileCode;
 
 
    public MobilecodeAuthenticationToken(String phone, String mobileCode) {
        super(null);
        this.phone = phone;
        this.mobileCode = mobileCode;
        this.setAuthenticated(false);
    }
 
    public MobilecodeAuthenticationToken(Object principal, Object credentials, Collection extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
 
    public Object getCredentials() {
        return this.credentials;
    }
 
    public Object getPrincipal() {
        return this.principal;
    }
 
    public String getPhone() {
        return phone;
    }
 
    public String getMobileCode() {
        return mobileCode;
    }
 
    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);
        }
    }
 
    public void eraseCredentials() {
        super.eraseCredentials();
        this.credentials = null;
    }
}
用户名密码

针对用户名密码方式,我们可以直接使用自带的DaoAuthenticationProvider以及对应的UsernamePasswordAuthenticationToken。

实现UserDetailService

UserDetailService服务用以返回当前登录用户的用户信息,可以每一种认证方式实现对应的UserDetailService,也可以使用同一个。这里我们使用同一个UserDetailService服务。(在provider中指定调用哪一个UserDetailService)

最后

在配置器中我们去实例化一个认证管理器AuthenticationManager,这个认证管理器中包含了两个认证器,分别是MobilecodeAuthenticationProvider(手机验证码)、DaoAuthenticationProvider(用户名密码)。

下面的只是名字不同改成自己的provider名字即可

相关推荐
User_芊芊君子6 分钟前
【Java String】类深度解析:从原理到高效使用技巧
java·开发语言
Pitayafruit21 分钟前
Spring AI 进阶之路02:集成SSE实现AI对话的流式响应
spring boot·后端·ai编程
xiaobin8899923 分钟前
IDEA 2025下载安装教程【超详细】保姆级图文教程(附安装包)
java·ide·其他·intellij-idea
小鱼人爱编程24 分钟前
Java基石--注解让你也能写框架
java·spring boot·后端
峰子大疯子25 分钟前
idea拉取新项目第一次启动报内存溢出(java.lang.OutOfMemoryError: Java heap space)
java·ide·intellij-idea
石头wang27 分钟前
关于 idea 里 properties 文件的中文乱码问题
java·ide·intellij-idea
鼠鼠我捏,要死了捏30 分钟前
基于Spring Boot Actuator与Prometheus的自定义指标监控与性能优化实战指南
spring boot·prometheus·monitoring
ChinaRainbowSea38 分钟前
Windows 安装 RabbitMQ 消息队列超详细步骤(附加详细操作截屏)
java·服务器·windows·后端·rabbitmq·ruby
一世暖阳7931 小时前
JDK、JRE、Eclipse
java·开发语言·eclipse
你我约定有三1 小时前
分布式微服务--GateWay(1)
java·开发语言·分布式·微服务·架构·gateway