若依前后端分离Spring Security新增手机号登录

备忘贴

转自:【若依RuoYi短信验证码登录】汇总_数据库_z_xiao_qiang-RuoYi 若依

配置Security:

按照Security的流程图可知,实现多种方式登录,只需要重写三个主要的组件,第一个用户认证处理过滤器,第二个用户认证token类,第三个,自定义短信登录身份认证。
在这里插入图片描述


/**
 * 参考UsernamePasswordAuthenticationToken类,继承AbstractAuthenticationToken,重写以下几个方法,自定义短信登录token验证。
 * 自定义短信登录token验证
 */
public class UsernamePhoneAuthenticationToken extends AbstractAuthenticationToken {

    /**
     * 手机号
     */
    private final Object principal;

    public UsernamePhoneAuthenticationToken(Object principals){
        super(null);
        this.principal = principals;
        setAuthenticated(false);
    }

    public UsernamePhoneAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities){
        super(authorities);
        this.principal = principal;
        super.setAuthenticated(true);
    }

    @Override
    public Object getCredentials() {
        return null;
    }

    @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");
        }
        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials(){
        super.eraseCredentials();
    }
/**
 * 重写UserDetailsService类的loadUserByUsername方法,实现用户验证处理。
 * 用户验证处理
 */
@Service("userDetailsByPhone")
public class UsernamePhoneUserDetailsServiceImpl implements UserDetailsService {

    private static final Logger logger = LoggerFactory.getLogger(UsernamePhoneUserDetailsServiceImpl.class);

    @Autowired
    private ISysUserService userService;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        SysUser sysUser;
        if(Pattern.compile("^[1][1,2,3,4,5,6,7,8,9][0-9]{9}$").matcher(username).matches()){
            sysUser = sysUserMapper.selectUserByTel(username);
        }else if(username.matches("\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-zA-Z0-9]{2,20}){1,2}")){
            sysUser = sysUserMapper.selectUserByEmail(username);
        }else{
            throw new ServiceException("请使用手机号或者邮箱进行登录!");
        }

        if(StringUtils.isNull(sysUser)){
            logger.info("登录用户:{} 不存在.", username);
            throw new ServiceException("登录用户:" + username+ " 不存在");
        }
        return createLoginUser(sysUser);
    }

    public UserDetails createLoginUser(SysUser user){
        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    }

/**
 * 自定义一个短信登录的身份鉴权, UserDetailsService 只负责根据用户名返回用户信息,AuthenticationProvider负责将 UserDetails 组装成 Authentication 向调用者返回。
 * 自定义短信登录身份认证
 */
public class UsernamePhoneAuthenticationProvider implements AuthenticationProvider {

    private UserDetailsService userDetailsService;

    public UsernamePhoneAuthenticationProvider(UserDetailsService userDetailsService){
        setUserDetailsService(userDetailsService);
    }

    /**
     * 重写authentication方法,实现身份验证逻辑
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePhoneAuthenticationToken authenticationToken = (UsernamePhoneAuthenticationToken) authentication;
        String phone = (String) authenticationToken.getPrincipal();
        //委托 UserDetailsService 查找系统用户
        UserDetails userDetails = userDetailsService.loadUserByUsername(phone);
        //鉴权成功,返回一个拥有鉴权的AbstractAuthenticationToken
        UsernamePhoneAuthenticationToken authenticationTokenRes = new UsernamePhoneAuthenticationToken(userDetails, userDetails.getAuthorities());
        authenticationTokenRes.setDetails(authenticationToken.getDetails());
        return authenticationTokenRes;
    }

    /**
     * 重写supports方法,指定此AuthenticationProvider 仅支持短信验证码身份验证
     */
    @Override
    public boolean supports(Class<?> authentication){
        return UsernamePhoneAuthenticationToken.class.isAssignableFrom(authentication);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }
/**
 * 配置SecurityConfig 的configure方法
 * spring security配置
 * 
 * @author victor_zhang
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
    /**
     * 自定义用户认证逻辑(账号密码)
     */
    @Autowired
    @Qualifier("userDetailsByPass")
    private UserDetailsService userDetailsService;

    /**
     * 自定义用户认证逻辑(手机号验证码)
     */
    @Autowired
    @Qualifier("userDetailsByPhone")
    private UserDetailsService userDetailsByPhone;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;
    
    //此处省略n行代码......

    /**
     * 身份认证接口
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        //手机或邮箱的验证码的验证
        auth.authenticationProvider(new UsernamePhoneAuthenticationProvider(userDetailsByPhone));
        //账号密码的验证       
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/676832.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux Shell脚本编写指南

大家好&#xff0c;在当今快节奏的科技时代&#xff0c;自动化和高效的工作流程对于个人和组织来说变得愈发重要。而Shell脚本编写作为一种强大且广泛应用的技能&#xff0c;成为了实现自动化任务和系统管理的利器。通过编写Shell脚本&#xff0c;我们可以将繁琐的重复任务自动…

【Matplotlib作图-4.Distribution】50 Matplotlib Visualizations, Python实现,源码可复现

目录 04 Distribution 4.0 Prerequisite 4.1 连续变量的直方图(Histogram for Continuous Variable) 4.2 分类变量的直方图(Histogram for Categorical Variable) 4.3 Density Plot 4.4 Density Curves with Histogram 4.5 Joy Plot 4.6 Distributed Dot Plot 4.7 Box P…

前端 video 实现全屏播放

只需要加上这句代码就行 controls <videoid"myVideo":src"detailDate.linkAddress":poster"detailDate.pictureUrl"enable-danmucontrolswebkit-playsinline"true"></video>

绘画参数配置及使用

绘画参数配置及使用 路径&#xff1a;站点后台-功能-AI绘画 进入参数配置 接口选择&#xff1a;多种接口自主选择&#xff08;需自己准备key&#xff09;&#xff0c;对应接口的key对话和绘画通用 存储空间&#xff1a; 位置在超管后台-存储空间 自主选择存储&#xff08;需…

【STL源码剖析】deque 的使用

别院深深夏席清&#xff0c;石榴开遍透帘明。 树阴满地日当午&#xff0c;梦觉流莺时一声。 目录 deque 的结构 deque 的迭代器剖析 deque 的使用 ​编辑 deque 的初始化 deque 的容量操作 deque 的访问操作 在 pos 位置插入另一个向量的 [forst&#xff0c;last] 间的数据​编…

JVMの堆、栈内存存储

1、JVM栈的数据存储 通过前面的学习&#xff0c;我们知道&#xff0c;将源代码编译成字节码文件后&#xff0c;JVM会对其中的字节码指令解释执行&#xff0c;在解释执行的过程中&#xff0c;又利用到了栈区的操作数栈和局部变量表两部分。 而局部变量表又分为一个个的槽位&…

web安全基础学习笔记

这里写目录标题 1.使用hackbar2.php漏洞基本分析 弱类型语言2.2 php漏洞找到隐藏的源代码之 index.php~2.3 php漏洞找到隐藏的源代码之 vim的临时文件 /.index.php.swp3.php漏洞基本分析 数组 3.php漏洞基本分析 extract4.php漏洞基本分析 strpos eregi函数漏洞4.php漏洞基本分…

Java web应用性能分析之【java进程问题分析定位】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客 由于篇幅限制、前面三篇讲了准备工作和分析小结&#xff0c;这里将详细操作java进程问题…

The First项目报告:去中心化知识产权治理协议MON Protocol如何革新链游产业?

2023年12月&#xff0c;RPG NFT 游戏 Pixelmon 首席执行官 GiulioX 在 X 平台表示&#xff0c;确认将推出代币 MON&#xff0c;代币生成&#xff08;TGE&#xff09;时间将取决于 MON 的路线图和主流 CEX 的启动板队列。12 月 11 日&#xff0c;RPG NFT 游戏 Pixelmon 首席执行…

防爆AGV叉车在现代物流行业的应用

AGV 随着机器人技术在中国的快速发展&#xff0c;国内企业开始推出区别于传统叉车的叉车AGV&#xff0c;旨在为企业降本增效&#xff0c;降低人工成本与对人的依赖&#xff1b;同时&#xff0c;也将人工从危险恶劣的环境中解放出来。随着技术的持续提升&#xff0c;叉车AGV已经…

API低代码平台介绍4-数据库记录插入功能

数据库记录插入功能 本篇文章我们将介绍如何使用ADI平台定义一个向目标数据库插入记录的接口&#xff0c;包括手工组装报文单表插入、手工组装报文多表插入、自动组装报文多表插入三种方式。无论是单表插入还是多表插入&#xff0c;任何一条记录写入失败&#xff0c;那么默认情…

kvm学习 - 迅速上手示例

目录 kvmtool kvmsample kvmtool GitHub - kvmtool/kvmtool: Stand-alone Native Linux KVM Tool repoStand-alone Native Linux KVM Tool repo. Contribute to kvmtool/kvmtool development by creating an account on GitHub.https://github.com/kvmtool/kvmtool.git cd …

17.Redis之主从复制

1.主从复制是怎么回事&#xff1f; 分布式系统, 涉及到一个非常关键的问题: 单点问题 单点问题&#xff1a;如果某个服务器程序, 只有一个节点(只搞一个物理服务器, 来部署这个服务器程序) 1.可用性问题,如果这个机器挂了,意味着服务就中断了~ 2.性能/支持的并发量也是比较有限…

C语言学习:数据类型

一、 为什么要引入数据类型 • 计算机中每个字节都有一个地址&#xff08;类似门牌号&#xff09; • CPU通过 地址 来访问这个字节的空间 0x20001103 1 0 0 1 0 0 1 1 0x20001102 1 1 1 0 1 1 1 0 0x20001101 1 1 1 1 0 1 0 1 0x20001100 0 …

【UML用户指南】-06-面向对象建模-关系(relationship)

目录 1、面向对象建模常见的关系 2、关系的组成元素 3、依赖关系 4、泛化关系 5、关联关系 关联的四种修饰 1.名称 2.角色 3.多重性 4.聚合 6、常用建模技术 6.1、对简单依赖建模 6.2、对单继承建模 6.3、对结构关系建模 1、面向对象建模常见的关系 依赖 &#x…

flask轻松入门,概念讲解

Hello World Flask 是轻量级web框架&#xff0c;仅保留了核心功能&#xff1a; 请求响应处理模板渲染URL路由 文章目录 Hello Worldflask命令模式python命令模式两种模式对比修改入口文件配置flask命令修改python命令修改 修改端口和地址flask命令修改python命令修改 修改 URL …

jupyter之plt 画图弹出窗口展示图片以及静态图片切换方法

1. jupyter出图的三种方式 在python的Jupyter Notebook中&#xff0c;使用matplotlib绘制动态图形时&#xff0c;可能出现只显示一张静态图像。 这是因为在notebook中使用plt绘图共有三种模式&#xff1a; %matplotlib inline&#xff1a;这是默认的模式&#xff0c;输出的图片…

JavaScript 基础 - 对象

对象 对象是一种无序的数据集合&#xff0c;可以详细的描述描述某个事物。 注意数组是有序的数据集合。它由属性和方法两部分构成。 语法 声明一个对象类型的变量与之前声明一个数值或字符串类型的变量没有本质上的区别。 <script>let 对象名 {属性名&#xff1a;属性值…

【OPENMV】学习记录 (持续更新)

一、图像 1 设置彩色&#xff0f;黑白&#xff1a; sensor.set_pixformat() 设置像素模式。 sensor.GRAYSCALE: 灰度&#xff0c;每个像素8bit。sensor.RGB565: 彩色&#xff0c;每个像素16bit。 2 设置图像大小&#xff1a; sensor.set_framesize() 设置图像的大小 sensor.…

前端优化之图片压缩——tinyPNG

今天前端前辈新介绍的一个压缩图片的工具——tinyPNG&#xff0c;地址&#xff1a;TinyPNG – Compress WebP, PNG and JPEG images intelligently可以将图片压缩&#xff0c;进行优化。 一、使用方法——手动压缩 将超过200kb的图片拖到我标注的红框框里&#xff0c;拖到这里…