赞
踩
本篇文章是对上篇文章所写代码的重构,重构内容包括以下两点
验证码基本参数可配置分为三级
需要做的具体工作
@RestController public class ValidateCodeController { public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE"; //session操作工具类 private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); //验证码生成逻辑封装类 @Autowired private ValidateCodeGenerator imageCodeGenerator; @GetMapping("/code/image") public void createImageCode(HttpServletRequest request, HttpServletResponse response) throws IOException { //1.生成ImageCode对象 ImageCode imageCode = imageCodeGenerator.generate(new ServletWebRequest(request)); //2.将ImageCode对象写入到session sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode); //3.将验证码写回到浏览器 ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream()); } }
package com.nrsc.security.core.validate.code;
import org.springframework.web.context.request.ServletWebRequest;
/**
* Created By: Sun Chuan
* Created Date: 2019/7/6 17:24
* Description: 以后还会有别的验证码生成逻辑,故将其统一定义出来
*/
public interface ValidateCodeGenerator {
ImageCode generate(ServletWebRequest request);
}
package com.nrsc.security.core.validate.code; import com.nrsc.security.core.properties.SecurityProperties; import lombok.Data; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.context.request.ServletWebRequest; import java.awt.*; import java.awt.image.BufferedImage; import java.util.Random; /** * Created By: Sun Chuan * Created Date: 2019/7/6 17:25 * Description: * (1)请求中可以传入高度和宽度 * (2)配置文件中可以配置高度、宽度、验证码的位数和过期时间 */ @Data public class ImageCodeGenerator implements ValidateCodeGenerator { public SecurityProperties securityProperties; @Override public ImageCode generate(ServletWebRequest request) { //ServletRequestUtils工具的作用是 //如果可以获取到请求中name为"width"的变量,将其转为int类型并作为返回值 //如果获取不到请求中name为"width"的变量,则将第三个参数进行返回即下面的securityProperties.getCode().getImage().getWidth() int width = ServletRequestUtils.getIntParameter(request.getRequest(), "width", securityProperties.getCode().getImage().getWidth()); int height = ServletRequestUtils.getIntParameter(request.getRequest(), "height", securityProperties.getCode().getImage().getHeight()); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200, 250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman", Font.ITALIC, 20)); g.setColor(getRandColor(160, 200)); for (int i = 0; i < 155; i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x, y, x + xl, y + yl); } String sRand = ""; for (int i = 0; i < securityProperties.getCode().getImage().getLength(); i++) { String rand = String.valueOf(random.nextInt(10)); sRand += rand; g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); g.drawString(rand, 13 * i + 6, 16); } g.dispose(); return new ImageCode(image, sRand, securityProperties.getCode().getImage().getExpireIn()); } private Color getRandColor(int fc, int bc) { Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } }
使用的是三级结构封装代码如下
package com.nrsc.security.core.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * "大盒子"类-----------------用于统一管理项目中所有由yml或properties文件传入的变量值 * Created By: Sun Chuan * Created Date: 2019/6/20 22:13 */ @Component //将此类注入到spring容器中 @Data //不用写get set方法了 @ConfigurationProperties(prefix = "nrsc.security") //指定以nrsc.security开头的配置会射入到该类中 public class SecurityProperties { //封装浏览器相关的属性 private BrowserProperties browser = new BrowserProperties(); //验证码相关的属性---可能包含图形验证码,短信验证码等,所以对其进行了又一次封装 private ValidateCodeProperties code = new ValidateCodeProperties(); }
package com.nrsc.security.core.properties;
import lombok.Data;
/**
* Created By: Sun Chuan
* Created Date: 2019/7/6 16:51
* Description: 验证码相关的封装类,之后还会有其他的验证码,所以将图片验证码,短信验证码等统一封装到该类里
*/
@Data
public class ValidateCodeProperties {
private ImageCodeProperties image = new ImageCodeProperties();
}
package com.nrsc.security.core.properties; import lombok.Data; /** * Created By: Sun Chuan * Created Date: 2019/7/6 16:50 */ @Data public class ImageCodeProperties { /**验证码的宽度*/ private int width = 67; /**验证码的高度*/ private int height = 23; /**验证码的位数*/ private int length = 4; /**验证码过期时间*/ private int expireIn = 60; }
应用级配置 — 在yml或者properties配置文件里进行配置
nrsc:
security:
code:
image:
length: 6 #图形验证码的位数为6,将覆盖默认配置中的4
width: 100 #图形验证码的宽度为100,将覆盖默认配置中的67,但由于请求中设置的宽度为200,
#所以真正的宽度将为200
请求级配置 — 即通过请求传入不同的参数,生成不同的图形验证码
<tr>
<td>图形验证码:</td>
<td>
<input type="text" name="imageCode">
<!--指定图形验证码的宽度为200,该配置为请求级配置,优先级最高-->
<img src="/code/image?width=200">
</td>
</tr>
package com.nrsc.security.core.validate.code; import com.nrsc.security.core.properties.SecurityProperties; 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; /** * Created By: Sun Chuan * Created Date: 2019/7/6 17:29 */ @Configuration public class ValidateCodeBeanConfig { @Autowired private SecurityProperties securityProperties; //@ConditionalOnMissingBean注解后面可以是name也可以是Type(XXX.class) //如果为name表示当spring容器里没有该名字的类时,被@ConditionalOnMissingBean注解的bean才可以注册到spring容器 //如果为type表示当spring容器里没有该类型的类时,被@ConditionalOnMissingBean注解的bean才可以注册到spring容器 //假如业务觉得我们提供的代码生成器太low,想换一个高大上的,比较好的做法不是随意改我们提供的默认代码 //而是自己实现一套逻辑覆盖掉我们的逻辑------》实际开发中这叫“增量开发” //记录一个问题---------------------------------------之后会慢慢去研究---------------------------------------- /*** * 其实我还一直有一个疑惑----》 * 比如说进行认证成功的代码开发时,只要我们实现AuthenticationSuccessHandler接口,当认证成功后就会走我们定义的 * 逻辑----》这是为什么??? * 肯定不是使用了@ConditionalOnMissingBean,因为使用该注解的话,spring-security默认实现了该接口的bean就不会 * 注入到spring容器中,但我们的逻辑却是 如果配置文件里传的为REDIRECT的话,就会调用spring-security默认的认证 * 成功逻辑---------》 */ //记录一个问题---------------------------------------之后会慢慢去研究------------------------------------------ @Bean @ConditionalOnMissingBean(name = "imageCodeGenerator") public ValidateCodeGenerator imageCodeGenerator() { ImageCodeGenerator codeGenerator = new ImageCodeGenerator(); codeGenerator.setSecurityProperties(securityProperties); return codeGenerator; } }
package com.nrsc.security.server.validate; import com.nrsc.security.core.validate.code.ImageCode; import com.nrsc.security.core.validate.code.ValidateCodeGenerator; import org.springframework.web.context.request.ServletWebRequest; /** * Created By: Sun Chuan * Created Date: 2019/7/6 19:03 */ //@Component("imageCodeGenerator") public class DemoImageCodeGenerator implements ValidateCodeGenerator { @Override public ImageCode generate(ServletWebRequest request) { System.out.println("更高级的图形验证码生成代码"); return null; } }
访问localhost:8080/demo.html,自动跳到下面的页面说明验证码 基本参数可配置已经生效
将2.4中的第二段代码的注释放开,再访问localhost:8080/demo.html,前端应该看不到验证码,且后端打出“更高级的图形验证码生成代码”,并报空指针异常
可以发现 验证码生成逻辑可配置已经生效
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。