Spring Boot Security自定义AuthenticationProvider

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

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

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

相关推荐

  1. 定义中间件

    2024-07-12 14:26:02       44 阅读
  2. 【VSCode】定义配置

    2024-07-12 14:26:02       33 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 14:26:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 14:26:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 14:26:02       58 阅读
  4. Python语言-面向对象

    2024-07-12 14:26:02       69 阅读

热门阅读

  1. 天童美语:推荐给孩子的人文历史纪录片

    2024-07-12 14:26:02       27 阅读
  2. 网站安全需求分析与安全保护工程

    2024-07-12 14:26:02       20 阅读
  3. 小米官网的数据是怎么优化的?

    2024-07-12 14:26:02       21 阅读
  4. 支付通道安全:应对黑客攻击的策略与实践

    2024-07-12 14:26:02       22 阅读
  5. Markdown 的详细语法介绍与使用

    2024-07-12 14:26:02       19 阅读
  6. OpenJudge | 比饭量

    2024-07-12 14:26:02       19 阅读
  7. 离线安装pip包

    2024-07-12 14:26:02       23 阅读
  8. 【MySQL】7.MySQL 的内置函数

    2024-07-12 14:26:02       20 阅读
  9. Spring 的核心注解

    2024-07-12 14:26:02       21 阅读