【Spring Security OAuth2】- spring security - 短信验证码接口发送

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

短信验证码接口发送

实现短信验证码登录

  • 开发短信验证码接口
  • 如何校验短信验证码
  • 重构代码

这里的套路与之前图形验证码的套路类似

开发短信验证码接口

    @RestController
    public class ValidateCodeController {
        public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
        private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    
        @Autowired
        private SecurityProperties securityProperties;
    
        @Autowired
        private ValidateCodeGenerate imageCodeGenerate;
    
        @Autowired
        private ValidateCodeGenerate smsCodeGenerate;
    
        @Autowired
        private SmsCodeSender smsCodeSender;
    
    
        @GetMapping("/code/sms")
        public void createSmsCode(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletRequestBindingException {
            ValidateCode validateCode = smsCodeGenerate.generate(request);
            String mobile = ServletRequestUtils.getRequiredStringParameter(request, "mobile");
            sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, validateCode.getCode());
            smsCodeSender.send(mobile, validateCode.getCode());
        }

配置类

    @Configuration
    public class ValidateCodeConfig {
        @Autowired
        private SecurityProperties securityProperties;
    
        // spring 容器中如果存在imageCodeGenerate的bean就不会再初始化该bean了
        // 条件注解
        @Bean
        @ConditionalOnMissingBean(name = "imageCodeGenerate")
        public ValidateCodeGenerate imageCodeGenerate() {
            ImageCodeGenerate imageCodeGenerate = new ImageCodeGenerate(securityProperties.getCode().getImage());
            return imageCodeGenerate;
        }
    
        // 这里由于产生了多个ValidateCodeGenerate的实现类
        // 所以需要使用name来区分
        // 在注入的时候也需要用其他手段与该name相同的id注入才可以
        // 当然还有其他的方式。可能可以使用:不同的子接口来分离短信和图形接口
        // 比如 @Qualifier("imageCodeGenerate") 或则什么的参数名和这个相同
        @Bean
        @ConditionalOnMissingBean(name = "smsCodeGenerate")
        public ValidateCodeGenerate smsCodeGenerate() {
            SmsCodeGenerate smsCodeGenerate = new SmsCodeGenerate(securityProperties.getCode().getSms());
            return smsCodeGenerate;
        }
    
        @Bean
        @ConditionalOnMissingBean(DefaultSmsCodeSender.class)
        public SmsCodeSender defaultSmsCodeSender() {
            return new DefaultSmsCodeSender();
        }
    }

短信验证码生成类

    package cn.mrcode.imooc.springsecurity.securitycore.validate.code.sms;
    
    import cn.mrcode.imooc.springsecurity.securitycore.properties.SmsCodeProperties;
    import cn.mrcode.imooc.springsecurity.securitycore.validate.code.ValidateCode;
    import cn.mrcode.imooc.springsecurity.securitycore.validate.code.ValidateCodeGenerate;
    import org.apache.commons.lang3.RandomStringUtils;
    
    import javax.servlet.http.HttpServletRequest;
    
    public class SmsCodeGenerate implements ValidateCodeGenerate {
        private SmsCodeProperties smsCodeProperties;
    
        public SmsCodeGenerate(SmsCodeProperties smsCodeProperties) {
            this.smsCodeProperties = smsCodeProperties;
        }
    
        @Override
        public ValidateCode generate(HttpServletRequest request) {
            int count = smsCodeProperties.getLength();
            int expireIn = smsCodeProperties.getExpireIn();
            String smsCode = RandomStringUtils.randomNumeric(count);
            return new ValidateCode(smsCode, expireIn);
        }

这里目前没有什么特别的,都是伪代码,提供一种思路。
还有就是贴出来的代码与之前图形验证码的部分代码重合了,就重构了;
由于发现有好多逻辑也是重复的。进行深度重构抽象。验证码处理器结构如下:

重构验证码逻辑

202306181903407581.png


虚线是调用

  • ValidateCodeController # 服务入口
  • ValidateCodeProcessor # 验证码处理接口
  • AbstractValidateCodeProcessor # 验证码处理 公共功能,使用模版方法模式聚合公共逻辑
  • ImageCodeProcessor # 图片验证码处理:响应
  • SmsCodeProcessor # 短信验证码处理:发送
  • ValidateCodeGenerator # 生成接口
  • ImageCodeGenerate # 图形验证码生成
  • SmsCodeGenerator # 短信验证码生成

上图逻辑清晰,看着么多类,实际上是把变化的部分抽象成接口了,公共的逻辑使用模版方法模式封装起来了;
以后可以应对不同的变化,比如:

  1. 图形验证码或则短信验证码的 生成逻辑变了,提供ValidateCodeGenerator实现类即可
  2. 图形或则短信验证码的响应/发送逻辑变了,提供AbstractValidateCodeProcessor的子类实现abstract void send发送方法

经过上面的思路分析,就是把变化的流程单独拿出来了。

这里涉及到一个spring中的开发技巧:依赖查找

    /**
     * <pre>
     * 收集系统中所有 {@link ValidateCodeGenerate} 接口的实现
     * spring开发技巧-依赖查找:
     *  spring会查找所有ValidateCodeGenerate的实现
     *  beanName做为key,实现作为value注入这里
     * </pre>
     */
    @Autowired
    private Map<String, ValidateCodeGenerate> validateCodeGenerates;
    
    在 AbstractValidateCodeProcessor 中声明的该参数;再来看下在其他地方是怎么初始化的
    
    @Configuration
    public class ValidateCodeConfig {
    
      @Bean
      @ConditionalOnMissingBean(name = "imageCodeGenerate")
      public ValidateCodeGenerate imageCodeGenerate() {
          ImageCodeGenerate imageCodeGenerate = new ImageCodeGenerate(securityProperties.getCode().getImage());
          return imageCodeGenerate;
      }
    
      @Bean
      @ConditionalOnMissingBean(name = "smsCodeGenerate")
      public ValidateCodeGenerate smsCodeGenerate() {
          SmsCodeGenerate smsCodeGenerate = new SmsCodeGenerate(securityProperties.getCode().getSms());
          return smsCodeGenerate;
      }
    }

上面使用了 条件排除,可以看出来这里有一个限制,就是短信和图形验证码的生成接口都使用的同一个;

那么这里在排除的时候就只能写上beanName来限制了;

对于上面的依赖查找技巧不会产生任何问题,但是对于使用处想替换该实现的时候。

对于bean的name只能是覆盖这里的同名name。否则就会出现配置不成功的问题

注意1:这里重构之后,会对 之前过滤器中的一部分代码有问题。
比如过滤器中图片验证码验证的地方SESSION_KEY的获取,目前处理是写死key的名称

注意2:这里只是针对发送接口做调整;不是验证功能;
仔细体会,这个接口的开发思路和使用的技巧超越自己好多年了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值