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

相关推荐
shenzhenNBA4 分钟前
如何在python项目中使用日志功能?通用版本
java·开发语言·python·日志·log
毕设源码-朱学姐5 分钟前
【开题答辩全过程】以 基于Vue Springboot的图书共享系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
m0_740043737 分钟前
Spring和SpringBoot和SpringMVC 的关系总结
java·spring boot·spring·mvc
float_com11 分钟前
【JavaWeb常见BUG】—— Lombok依赖失效问题
java·javaweb·bug分析与解决
通往曙光的路上13 分钟前
异步任务la
java·开发语言
SadSunset17 分钟前
(16)MyBatis执行流程分析(偏上层架构)
java·架构·mybatis
Tan_Ying_Y18 分钟前
JVM内存结构,什么是栈桢?
java·jvm
木井巳22 分钟前
【多线程】Thread类及常用方法
java·java-ee
小年糕是糕手28 分钟前
【C++】内存管理(下)
java·c语言·开发语言·数据结构·c++·算法
CoderYanger30 分钟前
第 479 场周赛Q2——3770. 可表示为连续质数和的最大质数
java·数据结构·算法·leetcode·职场和发展