zoukankan      html  css  js  c++  java
  • Spring Security构建Rest服务-0801-短信验证码发送

    实现短信验证码登录

      开发短信验证码接口

      校验短信验证码并登录

    短信验证码和图片验证码开发思路类似:

    1,我们访问一个controller

    2,在controller里调用短信验证码生成接口生成验证码

    3,验证码存进session

    4,从请求里获取手机号,调用短信发送服务商的接口,给手机号发送短信

    主要代码:

    1,短信验证码Controller:

    package com.imooc.security.core.validate.code;
    
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.social.connect.web.HttpSessionSessionStrategy;
    import org.springframework.social.connect.web.SessionStrategy;
    import org.springframework.web.bind.ServletRequestBindingException;
    import org.springframework.web.bind.ServletRequestUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.context.request.ServletWebRequest;
    
    import com.imooc.security.core.properties.SecurityProperties;
    import com.imooc.security.core.validate.code.sms.SmsCodeSender;
    
    /**
     * 验证码Control
     * ClassName: ValidateCodeController 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年3月1日
     */
    @RestController
    public class ValidateCodeController {
        
        public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";    
        
    //    @Autowired
    //    private SecurityProperties securityProperties;
        
        @Autowired
        private ValidateCodeGenerator imageCodeGenerator;//图片验证码
        
        @Autowired
        private ValidateCodeGenerator smsCodeGenerator;//短信验证码
        
        //获取session
        private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
        
        @Autowired
        private SmsCodeSender smsCodeSender; //短信验证码发送接口
        
      
        /**
         * 短信验证码
         * @Description: TODO
         * @param @param request
         * @param @param response
         * @param @throws IOException   
         * @return void  
         * @throws ServletRequestBindingException 
         * @throws
         * @author lihaoyang
         * @date 2018年3月7日
         */
        @GetMapping("/verifycode/sms")
        public void createSmsCode(HttpServletRequest request,HttpServletResponse response) throws Exception{
    
            //调验证码生成接口方式
            ValidateCode smsCode = smsCodeGenerator.generator(new ServletWebRequest(request));
            sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, smsCode);
            //获取手机号
            String mobile = ServletRequestUtils.getRequiredStringParameter(request, "mobile");
            //发送短信验证码
            smsCodeSender.send(mobile, smsCode.getCode());
        }
    
    }

    短信验证码生成实现类,实现验证码接口,验证码的长度和过期时间做成可配置的,灵活些:

    package com.imooc.security.core.validate.code;
    
    import org.apache.commons.lang.RandomStringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.ServletRequestUtils;
    import org.springframework.web.context.request.ServletWebRequest;
    
    import com.imooc.security.core.properties.SecurityProperties;
    
    /**
     * 短信验证码生成类
     * ClassName: ImageCodeGenerator 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年3月2日
     */
    @Component("smsCodeGenerator")
    public class SmsCodeGenerator implements ValidateCodeGenerator {
    
        @Autowired
        private SecurityProperties securityProperties;
        
        @Override
        public ValidateCode generator(ServletWebRequest request) {
            //生成验证码,长度从配置读取
            String code = RandomStringUtils.randomNumeric(securityProperties.getCode().getSms().getLength());
            return new ValidateCode(code, securityProperties.getCode().getSms().getExpireIn());
        }
    
        public SecurityProperties getSecurityProperties() {
            return securityProperties;
        }
    
        public void setSecurityProperties(SecurityProperties securityProperties) {
            this.securityProperties = securityProperties;
        }
        
    
    }

    验证码类:只有code和过期时间即可

    package com.imooc.security.core.validate.code;
    
    import java.awt.image.BufferedImage;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    
    /**
     * 短信验证码
     * ClassName: ImageCode 
     * @Description: 验证码
     * @author lihaoyang
     * @date 2018年3月1日
     */
    public class ValidateCode {
    
        
        private String code;
        
        private LocalDateTime expireTime;//过期时间点
        
        
        /**
         * 
         * <p>Description: </p>
         * @param image
         * @param code
         * @param expireTn 多少秒过期
         */
        public ValidateCode(String code, int expireTn) {
            this.code = code;
            //过期时间=当前时间+过期秒数 
            this.expireTime = LocalDateTime.now().plusSeconds(expireTn);
        }
    
        
        public ValidateCode(String code, LocalDateTime expireTime) {
            this.code = code;
            this.expireTime = expireTime;
        }
    
        /**
         * 验证码是否过期
         * @Description: 验证码是否过期
         * @param @return  true 过期,false 没过期
         * @return boolean   true 过期,false 没过期
         * @throws
         * @author lihaoyang
         * @date 2018年3月2日
         */
        public boolean isExpired(){
            return LocalDateTime.now().isAfter(expireTime);
        }
    
        
        public String getCode() {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        public LocalDateTime getExpireTime() {
            return expireTime;
        }
    
        public void setExpireTime(LocalDateTime expireTime) {
            this.expireTime = expireTime;
        }
    
    
        
    }

    验证码发送抽象成接口:

    package com.imooc.security.core.validate.code.sms;
    
    /**
     * 短信验证码发送接口
     * ClassName: SmsCodeSender 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年3月7日
     */
    public interface SmsCodeSender {
    
        /**
         * 发送验证码短信
         * @Description: 短信发送
         * @param @param mobile 接收验证码的手机号
         * @param @param code 验证码
         * @return void  
         * @throws
         * @author lihaoyang
         * @date 2018年3月7日
         */
        void send(String mobile,String code);
    }

    提供一个默认实现:做成引用该模块可覆盖默认实现的,更灵活

    package com.imooc.security.core.validate.code.sms;
    
    /**
     * 默认的短信验证码发送类
     * ClassName: DefaultSmsCodeSender 
     * @Description: TODO
     * @author lihaoyang
     * @date 2018年3月7日
     */
    public class DefaultSmsCodeSender implements SmsCodeSender{
    
        @Override
        public void send(String mobile, String code) {
            System.err.println("向手机 :"+mobile+" 发送短信验证码 :"+code);
        }
    
    }

    配置验证码生成器为spring的bean,,如果spring容器有该SmsCodeSender 接口的实现就用,没有了再配置,即可覆盖

    package com.imooc.security.core.validate.code;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.imooc.security.core.properties.SecurityProperties;
    import com.imooc.security.core.validate.code.sms.DefaultSmsCodeSender;
    import com.imooc.security.core.validate.code.sms.SmsCodeSender;
    
    /**
     * 配置验证码生成接口ValidateCodeGenerator的实际实现类的Bean
     * ClassName: ValidateCodeBeanConfig 
     * @Description: 
     *     配置验证码生成接口ValidateCodeGenerator的实际实现类的Bean
     *     如图片验证码的实现、短信验证码的实现
     * @author lihaoyang
     * @date 2018年3月5日
     */
    @Configuration
    public class ValidateCodeBeanConfig {
    
        @Autowired
        private SecurityProperties securityProperties;
        
        /**
         * @Description: 
         * 配置图片验证码生成bean
         * @ConditionalOnMissingBean注解意思是当spring容器不存在imageCodeGenerator时才给配置一个该bean
         * 作用是使程序更具可扩展性,该配置类是配置在core模块,这就意味着,如果引用该模块的项目
         * 如果有一个自己的实现,实现了ValidateCodeGenerator接口,定义了自己的实现,名字也叫imageCodeGenerator时,
         * 就用应用级别的实现,没有的话就用这个默认实现。
         * @param @return   
         * @return ValidateCodeGenerator  
         * @throws
         * @author lihaoyang
         * @date 2018年3月5日
         */
        @Bean
        @ConditionalOnMissingBean(name="imageCodeGenerator") 
        public ValidateCodeGenerator imageCodeGenerator(){ 
            ImageCodeGenerator codeGenerator = new ImageCodeGenerator();
            codeGenerator.setSecurityProperties(securityProperties);
            return codeGenerator;
        }
        
        /**
         * 配置短信验证码生成bean
         * @Description: 
         * @param @return   
         * @return SmsCodeSender  
         * @throws
         * @author lihaoyang
         * @date 2018年3月7日
         */
        @Bean
        @ConditionalOnMissingBean(SmsCodeSender.class)
        public SmsCodeSender smsCodeSender(){
            return new DefaultSmsCodeSender();
        }
    }

    验证码长度、过期时间配置类 SmsCodeProperties:

    package com.imooc.security.core.properties;
    
    /**
     * 短信验证码配置类
     * ClassName: ImageCodeProperties 
     * @Description: 图片验证码配置类
     * @author lihaoyang
     * @date 2018年3月2日
     */
    public class SmsCodeProperties {
    
        
        //验证码字符个数
        private int length = 4;
        //过期时间
        private int expireIn = 60;
        
        private String url; //拦截的url
    
    
    
        public int getLength() {
            return length;
        }
    
        public void setLength(int length) {
            this.length = length;
        }
    
        public int getExpireIn() {
            return expireIn;
        }
    
        public void setExpireIn(int expireIn) {
            this.expireIn = expireIn;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
        
        
    }

    登录表单:

    短信 登录 <br>
        <form action="/authentication/mobile" method="post">
            <table>
                <tr>
                    <td>手机号:</td>
                    <td><input type="text" name="mobile" value="13812349876"/></td>
                    <td></td>
                </tr>
                <tr>
                    <td>短信验证码:</td>
                    <td>
                        <input width="100" type="text" name="smsCode"/>
                        <a href="/verifycode/sms?mobile=13812349876">发送验证码</a>
                    </td>
                    <td></td>
                </tr>
                <tr>
                    <td>记住我</td>
                    <td><input type="checkbox" name="remember-me" value="true"/></td>
                </tr>
                <tr>
                    <td colspan="2" align="right"><button type="submit">登录</button></td>
                </tr>
            </table>
        </form>

    control打印:

  • 相关阅读:
    vue3配置rem适配
    webPack转vite2
    vite ant Design vue按需加载
    Vue3 +Vite+ts
    vite 2.0 动态引入加载图片
    Vue3使用vmdeditor自定义锚点
    ThinkPHP6 路由
    DIV+CSS 文本属性
    DIV+CSS 入门篇 CSS选择器
    如何不使用react,也能解析jsx?
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/8522172.html
Copyright © 2011-2022 走看看