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名字即可

相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
冰帝海岸3 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象4 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了4 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
小二·4 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
懒洋洋大魔王5 小时前
RocketMQ的使⽤
java·rocketmq·java-rocketmq
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
qq_17448285755 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序
转世成为计算机大神5 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式