【Spring Security + OAuth2 + JWT入门到实战】10. 改造优化获取图形验证码和短信验证码

|▌冷眼眸甩不掉的悲伤 提交于 2020-03-04 13:06:23

简介

在获取图形验证码和短信验证码有很多重复的代码本次会优化这些代码。

项目文件结构

验证码处理器代码结构

虚线是调用

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

ValidateCodeProcessor

com.spring.security.validate.code路径创建ValidateCodeProcessor类,生成验证码入口

package com.spring.security.validate.code;

import org.springframework.web.context.request.ServletWebRequest;

/**
 * 校验码处理器,封装不同校验码的处理逻辑
 *
 */
public interface ValidateCodeProcessor {

	/**
	 * 验证码放入session时的前缀
	 */
	String SESSION_KEY_PREFIX = "SESSION_KEY_FOR_CODE_";

	/**
	 * 创建校验码
	 * 
	 * @param request
	 * @throws Exception
	 */
	void createCode(ServletWebRequest request) throws Exception;

}

 

AbstractValidateCodeProcessor

验证码处理 公共功能,使用模版方法模式聚合公共逻辑

com.spring.security.validate.code.impl路径创建AbstractValidateCodeProcessor类

package com.spring.security.validate.code.impl;

import java.util.Map;

import com.spring.security.validate.code.ValidateCodeException;
import org.apache.commons.lang.StringUtils;
import com.spring.security.validate.code.ValidateCode;
import com.spring.security.validate.code.ValidateCodeGenerator;
import com.spring.security.validate.code.ValidateCodeProcessor;
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.context.request.ServletWebRequest;

public abstract class AbstractValidateCodeProcessor<C extends ValidateCode> implements ValidateCodeProcessor {

    /**
     * 操作session的工具类
     */
    private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    /**
     * 收集系统中所有的 {@link ValidateCodeGenerator} 接口的实现。
     */
    @Autowired
    private Map<String, ValidateCodeGenerator> validateCodeGenerators;

    /**
     * ValidateCodeProcessor
     */
    @Override
    public void createCode(ServletWebRequest request) throws Exception {
        C validateCode = generate(request);
        save(request, validateCode);
        send(request, validateCode);
    }

    /**
     * 生成校验码
     *
     * @param request
     * @return
     */
    @SuppressWarnings("unchecked")
    private C generate(ServletWebRequest request) {
        String type = getProcessorType(request);
        ValidateCodeGenerator validateCodeGenerator = validateCodeGenerators.get(type + "CodeGenerator");
        if (validateCodeGenerator == null) {
            throw new ValidateCodeException("验证码生成器" + type + "CodeGenerator不存在");
        }
        return (C) validateCodeGenerator.createCode(request);
    }

    /**
     * 保存校验码
     *
     * @param request
     * @param validateCode
     */
    private void save(ServletWebRequest request, C validateCode) {
        sessionStrategy.setAttribute(request, SESSION_KEY_PREFIX + getProcessorType(request).toUpperCase(), validateCode);
    }

    /**
     * 发送校验码,由子类实现
     *
     * @param request
     * @param validateCode
     * @throws Exception
     */
    protected abstract void send(ServletWebRequest request, C validateCode) throws Exception;

    /**
     * 根据请求的url获取校验码的类型
     *
     * @param request
     * @return
     */
    private String getProcessorType(ServletWebRequest request) {
        return StringUtils.substringAfter(request.getRequest().getRequestURI(), "/code/");
    }


}

 

ImageCodeProcessor

com.spring.security.validate.code.image路径创建ImageCodeProcessor图片验证码处理:响应

/**
 * 
 */
package com.spring.security.validate.code.image;

import javax.imageio.ImageIO;

import com.spring.security.validate.code.impl.AbstractValidateCodeProcessor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;


/**
 * 图片验证码处理器
 *
 */
@Component("imageCodeProcessor")
public class ImageCodeProcessor extends AbstractValidateCodeProcessor<ImageCode> {

	/**
	 * 发送图形验证码,将其写到响应中
	 */
	@Override
	protected void send(ServletWebRequest request, ImageCode imageCode) throws Exception {
		ImageIO.write(imageCode.getImage(), "JPEG", request.getResponse().getOutputStream());
	}
}

 

SmsCodeProcessor

com.spring.security.validate.code.sms路径创建SmsCodeProcessor短信验证码处理:发送

/**
 *
 */
package com.spring.security.validate.code.sms;

import com.spring.security.validate.code.ValidateCode;
import com.spring.security.validate.code.impl.AbstractValidateCodeProcessor;
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;

/**
 * 短信验证码处理器
 *
 */
@Component("smsCodeProcessor")
public class SmsCodeProcessor extends AbstractValidateCodeProcessor<ValidateCode> {

    /**
     * 短信验证码发送器
     */
    @Autowired
    private SmsCodeSender smsCodeSender;

    @Override
    protected void send(ServletWebRequest request, ValidateCode validateCode) throws Exception {
        //获取手机号
        String mobile = ServletRequestUtils.getRequiredStringParameter(request.getRequest(), "mobile");
        //发送短信
        smsCodeSender.send(mobile, validateCode.getCode());
    }

}

 

修改控制器

改造ValidateController类统一访问路径

package com.spring.security.validate.code;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * 获取验证码控制器
 */
@RestController
public class ValidateController {

    @Autowired
    private Map<String, ValidateCodeProcessor> validateCodeProcessor;

    /**
     * 创建验证码,根据验证码类型不同,调用不同的 {@link ValidateCodeProcessor}接口实现
     *
     * @param request
     * @param response
     * @param type
     * @throws Exception
     */
    @GetMapping("/code/{type}")
    public void createCode(HttpServletRequest request, HttpServletResponse response, @PathVariable String type)
            throws Exception {
        validateCodeProcessor.get(type + "CodeProcessor").createCode(new ServletWebRequest(request, response));
    }
}

 

修改图形验证码拦截器

修改ValidateCodeFilter类的validateCode方法:

ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(servletWebRequest, "SESSION_KEY_FOR_CODE_IMAGE");

session值我们先写死,等做到短信验证码拦截器一起优化掉。

 

测试

启动项目访问:http://127.0.0.1:8080/signIn.html

获取图形验证码没问题,输入正确验证码账号登录:

 

重启项目测试获取短信验证:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!