JavaWeb-SpringSecurity使用短信验证码登陆

 

 

  相关博文

  JavaWeb-SpringBoot_一个类实现腾讯云SDK发送短信  传送门

 

  系列博文

  项目已上传至guthub  传送门

  JavaWeb-SpringSecurity初认识  传送门

  JavaWeb-SpringSecurity在数据库中查询登陆用户  传送门

  JavaWeb-SpringSecurity自定义登陆页面  传送门

  JavaWeb-SpringSecurity实现需求-判断请求是否以html结尾  传送门

  JavaWeb-SpringSecurity自定义登陆配置  传送门

  JavaWeb-SpringSecurity图片验证ImageCode  传送门

  JavaWeb-SpringSecurity记住我功能  传送门

  JavaWeb-SpringSecurity使用短信验证码登陆  传送门

 

  在项目GaryRESTful.validate.code包下创建SmsCode.java

package com.Gary.GaryRESTful.validate.code;

import java.time.LocalDateTime;

public class SmsCode {

    //发送短信code
    private String code;
    
    //当前系统时间
    private LocalDateTime expireTime;

    public SmsCode(String code,int exprieTime)
    {
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(exprieTime);
    }
    
    public SmsCode(String code,LocalDateTime expireTime)
    {
        this.code = code;
        this.expireTime = expireTime;
    }
    
    //判断当前时间是否存在过期之后
    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;
    }
    
    
    
}
SmsCode.java

  

  优化ImageCode.java与SmsCode.java,将SmsCode.java重命名为ValidateCode.java,并用ImageCode.java继承ValidateCode.java

package com.Gary.GaryRESTful.validate.code;

import java.time.LocalDateTime;

public class ValidateCode {

    //发送短信code
    private String code;
    
    //当前系统时间
    private LocalDateTime expireTime;

    public ValidateCode(String code,int expireTime)
    {
        this.code = code;
        this.expireTime = LocalDateTime.now().plusSeconds(expireTime);
    }
    
    public ValidateCode(String code,LocalDateTime expireTime)
    {
        this.code = code;
        this.expireTime = expireTime;
    }
    
    //判断当前时间是否存在过期之后
    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;
    }
    
    
    
}
ValidateCode.java

 

  导入腾讯云发短信qcloudsms-1.0.5.jar包

  

 

 

  ValidateCodeController.java中实现接收发送短信验证码的请求@GetMapping("/code/sms")

    @GetMapping("/code/sms")    
    public void createSmsCode(HttpServletRequest request,HttpServletResponse response) throws ServletRequestBindingException
    {
        //生成短信的校验码
        ValidateCode smsCode = createSmsCode();
        //将我们的校验码放入session域中
        sessionStrategy.setAttribute(new ServletWebRequest(request), sessionSmsKey, smsCode);
        //从request域中获取手机号
        String mobile = ServletRequestUtils.getRequiredStringParameter(request, "mobile");
        //发短信(给mobile手机号发送smsCode验证码)
        sendSms(mobile,smsCode.getCode());
    }
    
    //发短信(给mobile手机号发送smsCode验证码)
    private void sendSms(String mobile, String code) {
        //1.腾讯云自己项目的AppID
        int appid = 1400182502;
        
        String appkey = "58f61b731363faba756087b9504bff46";

        int templateId =193928;
        
        String smsSign = "Garyd公众号";
        
        String phoneNumber = mobile;
        
        String[] params = new String[1];
        params[0] = code;
        //将验证码打印出来
        System.out.println("验证码: "+code);
        
        SmsSingleSender sender = new SmsSingleSender(appid,appkey);
        
        //86,手机号,模板id,验证码,smsSign
        try {
            SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumber, templateId, params, smsSign, "", "");
        
            //打印是否发送成功
            System.out.println(result);
        } catch (JSONException | HTTPException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    //生成短信的校验码
    private ValidateCode createSmsCode() {
        Random r = new Random();
        String code = "" +r.nextInt(10)+r.nextInt(10)+r.nextInt(10)+r.nextInt(10);
        return new ValidateCode(code,120);
    }

 

  别忘了在SecurityConfig.java中的configure()方法中打开对/code/sms请求的拦截

//在访问我们的URL时,我们是不需要省份认证,可以立即访问
            .antMatchers("/login.html","/require","/code/image","/code/sms").permitAll()

 

  测试

  发送验证码请求  localhost:8080/code/sms?mobile=17689470428

 

 

  后台result信息输出

  

  【出现result:1031错误表示短信包没钱了!( ╯□╰ )窘迫~】

 

  当短信发送成功时,result返回值是0,返回值是"OK"

  

 

  【当控制台输出result第一个参数为 0 后稍等几秒手机便会接收腾讯云发送的短信】

 

#datasource
spring.datasource.url=jdbc:mysql:///springsecurity?serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.dricer-class-name=com.mysql.jdbc.Driver

#jpa
#打印出数据库语句
spring.jpa.show-sql=true
#更新数据库表
spring.jpa.hibernate.ddl-auto=update

#配置登陆方式
gary.security.loginType = JSON

server.port=8080

#验证码长度
gary.security.code.image.length = 6
#验证码图片的长
gary.security.code.image.width = 100

#配置哪些需要我们验证码的Filter
gary.security.code.image.url = /user,/user/*

#Token过期时间
gary.security.rememberMeSeconds = 3600
application.properties

 

package com.Gary.GaryRESTful.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import com.Gary.GaryRESTful.filter.ValidateCodeFilter;
import com.Gary.GaryRESTful.handler.LoginFailureHandler;
import com.Gary.GaryRESTful.handler.LoginSuccessHandler;
import com.Gary.GaryRESTful.properties.GarySecurityProperties;


//Web应用安全适配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    //告诉SpringSecurity密码用什么加密的
    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
    
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;
     
    @Autowired
    private GarySecurityProperties garySecurityProperties;
    
    @Autowired    
    private DataSource dataSource;
    
    //负责操作数据库
    public PersistentTokenRepository  persistentTokenRepository()
    {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }
    
    @Autowired    
    public UserDetailsService userDetailService;
    
    
    protected void configure(HttpSecurity http) throws Exception{
        
        //声明我们自己写的过滤器
        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        //给过滤器赋值
        validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
        validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
        validateCodeFilter.afterPropertiesSet();
        
        //表单验证(身份认证)
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
            .formLogin()
            //自定义登陆页面
            .loginPage("/require")
            //如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
            .loginProcessingUrl("/loginPage")
            //配置登陆成功调用loginSuccessHandler
            .successHandler(loginSuccessHandler)
            //配置登陆失败调用loginFailureHandler
            .failureHandler(loginFailureHandler)
            //记住我功能
            .and()
            .rememberMe()
            //配置persistentTokenRepository
            .tokenRepository(persistentTokenRepository())
            //配置过期秒数
            .tokenValiditySeconds(garySecurityProperties.getRememberMeSeconds())
            //配置userDetailsService
            .userDetailsService(userDetailService)
            .and()
            //请求授权
            .authorizeRequests()
            //在访问我们的URL时,我们是不需要省份认证,可以立即访问
            .antMatchers("/login.html","/require","/code/image","/code/sms").permitAll()
            //所有请求都被拦截,跳转到(/login请求中)
            .anyRequest()
            //都需要我们身份认证
            .authenticated()
            //SpringSecurity保护机制
            .and().csrf().disable();
    }
    
}
SecurityConfig.java

 

package com.Gary.GaryRESTful.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
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.Gary.GaryRESTful.properties.GarySecurityProperties;
import com.Gary.GaryRESTful.validate.code.ImageCode;
import com.Gary.GaryRESTful.validate.code.ValidateCode;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;

@RestController
public class ValidateCodeController {
    
    //操作Session
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    
    public static String sessionKey = "session_key_image_code";

    public static String sessionSmsKey = "session_key_sms_code";
    
    @Autowired
    private GarySecurityProperties garySecurityProperties;
    
    
    @GetMapping("/code/sms")    
    public void createSmsCode(HttpServletRequest request,HttpServletResponse response) throws ServletRequestBindingException
    {
        //生成短信的校验码
        ValidateCode smsCode = createSmsCode();
        //将我们的校验码放入session域中
        sessionStrategy.setAttribute(new ServletWebRequest(request), sessionSmsKey, smsCode);
        //从request域中获取手机号
        String mobile = ServletRequestUtils.getRequiredStringParameter(request, "mobile");
        //发短信(给mobile手机号发送smsCode验证码)
        sendSms(mobile,smsCode.getCode());
    }
    
    //发短信(给mobile手机号发送smsCode验证码)
    private void sendSms(String mobile, String code) {
        //1.腾讯云自己项目的AppID
        int appid = 1400184301;
        
        String appkey = "58f61b731363faba756087b9504bff46";
        
        //短信正文的id
        int templateId =275243;
        
        String smsSign = "Garyd公众号";
        
        String phoneNumber = mobile;
        
        String[] params = new String[1];
        params[0] = code;
        //将验证码打印出来
        System.out.println("验证码: "+code);
        
        SmsSingleSender sender = new SmsSingleSender(appid,appkey);
        
        //86,手机号,模板id,验证码,smsSign
        try {
            SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumber, templateId, params, smsSign, "", "");
        
            //打印是否发送成功
            System.out.println(result);
        } catch (JSONException | HTTPException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    //生成短信的校验码
    private ValidateCode createSmsCode() {
        Random r = new Random();
        String code = "" +r.nextInt(10)+r.nextInt(10)+r.nextInt(10)+r.nextInt(10);
        return new ValidateCode(code,120);
    }


    @GetMapping("/code/image")
    public void createCode(HttpServletRequest request,HttpServletResponse response) throws IOException
    {
        //生成随机数的图片
        ImageCode imageCode = createImageCode(request);
        
        //将随机数放入到session中
        sessionStrategy.setAttribute(new ServletWebRequest(request), sessionKey, imageCode);
        
        //将我们生成的图片写到接口的响应的输出流中
        ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());
        
    }
    
    //生成图片验证码(验证码,图片,失效的时间)
    private ImageCode createImageCode(HttpServletRequest request)
    {
        //定义图片的长和宽
        int width = ServletRequestUtils.getIntParameter(request, "width", garySecurityProperties.getCode().getImage().getWidth());
        int height =  ServletRequestUtils.getIntParameter(request, "height", garySecurityProperties.getCode().getImage().getHeight());;
        
        //生成一张图片
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        
        //获得画笔工具
        Graphics g = image.getGraphics();
        
        //画一个矩形
        g.setColor(new Color(255,255,255));
        g.fillRect(0, 0, width, height);
        
        //画干扰线
        g.setColor(new Color(0,0,0));
        //设置字体
        g.setFont(new Font("Time New Roman",Font.ITALIC,20));
        Random random = new Random();
        
        for(int i=0;i<20;i++)
        {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(12);
            int y1 = random.nextInt(12);
            //(x,y)到(x+x1,y+y1)
            g.drawLine(x, y, x+x1, y+y1);
        }
        
        //画数据
        String sRand = "";
        for(int i = 0;i<garySecurityProperties.getCode().getImage().getLength();i++)
        {
            String rand =String.valueOf(random.nextInt(10));
            //System.out.println(rand);
            sRand += rand;
            //每一个字都改变一下颜色
            g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
            //画每一个数据
            g.drawString(rand, 13*i, 16);
        }
        
        g.dispose();
        
        //生成我们自己的验证码数据(图片,验证码,过期时间)
        return new ImageCode(image,sRand,garySecurityProperties.getCode().getImage().getExpireIn());
    }
    
    public SessionStrategy getSessionStrategy() {
        return sessionStrategy;
    }

    public void setSessionStrategy(SessionStrategy sessionStrategy) {
        this.sessionStrategy = sessionStrategy;
    }

    public static String getSessionKey() {
        return sessionKey;
    }

    public static void setSessionKey(String sessionKey) {
        ValidateCodeController.sessionKey = sessionKey;
    }


    
}
ValidateCodeController.java

 

  在GaryRESTful.properties包下创建SmsCodeProperties.java,配置Sms发送短信的配置

package com.Gary.GaryRESTful.properties;

public class SmsCodeProperties {

    private int length = 6;
    private int expireIn = 120;
    private String 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;
    }
    
    
    
}
SmsCodeProperties.java

 

  优化ImageCodeProperties.java与SmsCodeProperties.java,将ImageCodeProperties.java继承SmsCodeProperties.java,并于少写代码

package com.Gary.GaryRESTful.properties;

public class ImageCodeProperties extends SmsCodeProperties{

    private int width = 67;
    private int height = 23;
    
    public ImageCodeProperties()
    {
        setLength(4);
    }
    
    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    
    
}
ImageCodeProperties.java

 

  在login.html中添加填写手机验证码<input>,发送验证码的手机号我们给个定值value=17689470428,发送请求时都是通过ajax去进行数据交互,这里直接给个定制,通过<a>标签去访问请求/code/sms?mobile=17689470428(手机号不变)

    <form action="">
    
        手机号:
        <input type="text" name=“mobile” value="17689470428">
        <br>
        短信验证码:
        <input type="text" name="smsCode">
        <a href="/code/sms?mobile=17689470428">发送短信验证码</a>
        
        <input type = "submit">
    </form>

 

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Gary登陆页面</h1>
    <form action="/loginPage" method="post">
    
        用户名:
        <input type="text" name="username">
        <br>
        
        密码:
        <input type="password" name="password">
        <br>
        
        图片验证码:
        <input type="text" name="imageCode">
        <img src="/code/image">
        <br>
        
        <input name="remember-me" type="checkbox" value="true">
        记住我
        
        <input type="submit">
    
    </form>
    
    <br>
    <hr>
    <br>
    <form action="">
    
        手机号:
        <input type="text" name=“mobile” value="17689470428">
        <br>
        短信验证码:
        <input type="text" name="smsCode">
        <a href="/code/sms?mobile=17689470428">发送短信验证码</a>
        
        <input type = "submit">
    </form>

</body>
</html>
login.html

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Gary登陆页面</h1>
    <form action="/loginPage" method="post">
    
        用户名:
        <input type="text" name="username">
        <br>
        
        密码:
        <input type="password" name="password">
        <br>
        
        图片验证码:
        <input type="text" name="imageCode">
        <img src="/code/image">
        <br>
        
        <input name="remember-me" type="checkbox" value="true">
        记住我
        
        <input type="submit">
    
    </form>
    
    <br>
    <hr>
    <br>
    <form action="">
    
        手机号:
        <input type="text" name=“mobile” value="17689470428">
        <br>
        短信验证码:
        <input type="text" name="smsCode">
        <a href="/code/sms?mobile=17689470428">发送短信验证码</a>
        
        <input type = "submit">
    </form>

</body>
</html>
login.html

 

#datasource
spring.datasource.url=jdbc:mysql:///springsecurity?serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.dricer-class-name=com.mysql.jdbc.Driver

#jpa
#打印出数据库语句
spring.jpa.show-sql=true
#更新数据库表
spring.jpa.hibernate.ddl-auto=update

#配置登陆方式
gary.security.loginType = JSON

server.port=8080

#验证码长度
gary.security.code.image.length = 6
#验证码图片的长
gary.security.code.image.width = 100

#配置哪些需要我们验证码的Filter
gary.security.code.image.url = /user,/user/*

#Token过期时间
gary.security.rememberMeSeconds = 3600
application.properties

 

package com.Gary.GaryRESTful.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import com.Gary.GaryRESTful.filter.ValidateCodeFilter;
import com.Gary.GaryRESTful.handler.LoginFailureHandler;
import com.Gary.GaryRESTful.handler.LoginSuccessHandler;
import com.Gary.GaryRESTful.properties.GarySecurityProperties;


//Web应用安全适配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    //告诉SpringSecurity密码用什么加密的
    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
    
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;

    @Autowired
    private LoginFailureHandler loginFailureHandler;
     
    @Autowired
    private GarySecurityProperties garySecurityProperties;
    
    @Autowired    
    private DataSource dataSource;
    
    //负责操作数据库
    public PersistentTokenRepository  persistentTokenRepository()
    {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }
    
    @Autowired    
    public UserDetailsService userDetailService;
    
    
    protected void configure(HttpSecurity http) throws Exception{
        
        //声明我们自己写的过滤器
        ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        //给过滤器赋值
        validateCodeFilter.setAuthenticationFailureHandler(loginFailureHandler);
        validateCodeFilter.setGarySecurityProperties(garySecurityProperties);
        validateCodeFilter.afterPropertiesSet();
        
        //表单验证(身份认证)
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
            .formLogin()
            //自定义登陆页面
            .loginPage("/require")
            //如果URL为loginPage,则用SpringSecurity中自带的过滤器去处理该请求
            .loginProcessingUrl("/loginPage")
            //配置登陆成功调用loginSuccessHandler
            .successHandler(loginSuccessHandler)
            //配置登陆失败调用loginFailureHandler
            .failureHandler(loginFailureHandler)
            //记住我功能
            .and()
            .rememberMe()
            //配置persistentTokenRepository
            .tokenRepository(persistentTokenRepository())
            //配置过期秒数
            .tokenValiditySeconds(garySecurityProperties.getRememberMeSeconds())
            //配置userDetailsService
            .userDetailsService(userDetailService)
            .and()
            //请求授权
            .authorizeRequests()
            //在访问我们的URL时,我们是不需要省份认证,可以立即访问
            .antMatchers("/login.html","/require","/code/image","/code/sms").permitAll()
            //所有请求都被拦截,跳转到(/login请求中)
            .anyRequest()
            //都需要我们身份认证
            .authenticated()
            //SpringSecurity保护机制
            .and().csrf().disable();
    }
    
}
SecurityConfig.java

 

package com.Gary.GaryRESTful.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
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.Gary.GaryRESTful.properties.GarySecurityProperties;
import com.Gary.GaryRESTful.validate.code.ImageCode;
import com.Gary.GaryRESTful.validate.code.ValidateCode;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;

@RestController
public class ValidateCodeController {
    
    //操作Session
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    
    public static String sessionKey = "session_key_image_code";

    public static String sessionSmsKey = "session_key_sms_code";
    
    @Autowired
    private GarySecurityProperties garySecurityProperties;
    
    
    @GetMapping("/code/sms")    
    public void createSmsCode(HttpServletRequest request,HttpServletResponse response) throws ServletRequestBindingException
    {
        //生成短信的校验码
        ValidateCode smsCode = createSmsCode();
        //将我们的校验码放入session域中
        sessionStrategy.setAttribute(new ServletWebRequest(request), sessionSmsKey, smsCode);
        //从request域中获取手机号
        String mobile = ServletRequestUtils.getRequiredStringParameter(request, "mobile");
        //发短信(给mobile手机号发送smsCode验证码)
        sendSms(mobile,smsCode.getCode());
    }
    
    //发短信(给mobile手机号发送smsCode验证码)
    private void sendSms(String mobile, String code) {
        //1.腾讯云自己项目的AppID
        int appid = 1400184301;
        
        String appkey = "58f61b731363faba756087b9504bff46";
        
        //短信正文的id
        int templateId =275243;
        
        String smsSign = "Garyd公众号";
        
        String phoneNumber = mobile;
        
        String[] params = new String[1];
        params[0] = code;
        //将验证码打印出来
        System.out.println("验证码: "+code);
        
        SmsSingleSender sender = new SmsSingleSender(appid,appkey);
        
        //86,手机号,模板id,验证码,smsSign
        try {
            SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumber, templateId, params, smsSign, "", "");
        
            //打印是否发送成功
            System.out.println(result);
        } catch (JSONException | HTTPException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

    //生成短信的校验码
    private ValidateCode createSmsCode() {
        Random r = new Random();
        String code = "" ;
        for(int i=0;i<garySecurityProperties.getCode().getSms().getLength();i++)
        {
            code += r.nextInt(10);
        }
        return new ValidateCode(code,garySecurityProperties.getCode().getSms().getExpireIn());
    }


    @GetMapping("/code/image")
    public void createCode(HttpServletRequest request,HttpServletResponse response) throws IOException
    {
        //生成随机数的图片
        ImageCode imageCode = createImageCode(request);
        
        //将随机数放入到session中
        sessionStrategy.setAttribute(new ServletWebRequest(request), sessionKey, imageCode);
        
        //将我们生成的图片写到接口的响应的输出流中
        ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());
        
    }
    
    //生成图片验证码(验证码,图片,失效的时间)
    private ImageCode createImageCode(HttpServletRequest request)
    {
        //定义图片的长和宽
        int width = ServletRequestUtils.getIntParameter(request, "width", garySecurityProperties.getCode().getImage().getWidth());
        int height =  ServletRequestUtils.getIntParameter(request, "height", garySecurityProperties.getCode().getImage().getHeight());;
        
        //生成一张图片
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        
        //获得画笔工具
        Graphics g = image.getGraphics();
        
        //画一个矩形
        g.setColor(new Color(255,255,255));
        g.fillRect(0, 0, width, height);
        
        //画干扰线
        g.setColor(new Color(0,0,0));
        //设置字体
        g.setFont(new Font("Time New Roman",Font.ITALIC,20));
        Random random = new Random();
        
        for(int i=0;i<20;i++)
        {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int x1 = random.nextInt(12);
            int y1 = random.nextInt(12);
            //(x,y)到(x+x1,y+y1)
            g.drawLine(x, y, x+x1, y+y1);
        }
        
        //画数据
        String sRand = "";
        for(int i = 0;i<garySecurityProperties.getCode().getImage().getLength();i++)
        {
            String rand =String.valueOf(random.nextInt(10));
            //System.out.println(rand);
            sRand += rand;
            //每一个字都改变一下颜色
            g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
            //画每一个数据
            g.drawString(rand, 13*i, 16);
        }
        
        g.dispose();
        
        //生成我们自己的验证码数据(图片,验证码,过期时间)
        return new ImageCode(image,sRand,garySecurityProperties.getCode().getImage().getExpireIn());
    }
    
    public SessionStrategy getSessionStrategy() {
        return sessionStrategy;
    }

    public void setSessionStrategy(SessionStrategy sessionStrategy) {
        this.sessionStrategy = sessionStrategy;
    }

    public static String getSessionKey() {
        return sessionKey;
    }

    public static void setSessionKey(String sessionKey) {
        ValidateCodeController.sessionKey = sessionKey;
    }


    
}
ValidateCodeController.java

 

package com.Gary.GaryRESTful.properties;

public class ValidateCodeProperties {

    //图片验证码
    private ImageCodeProperties image = new ImageCodeProperties();

    private SmsCodeProperties sms = new SmsCodeProperties();
    
    
    
    
    public SmsCodeProperties getSms() {
        return sms;
    }

    public void setSms(SmsCodeProperties sms) {
        this.sms = sms;
    }

    public ImageCodeProperties getImage() {
        return image;
    }

    public void setImage(ImageCodeProperties image) {
        this.image = image;
    }
    
    
    
}
ValidateCodeProperties.java

 

 

 

 

 

 

 

 

 

posted @ 2019-11-08 16:18  Cynical丶Gary  阅读(440)  评论(0编辑  收藏  举报