【shiro】13.验证码过滤器

通过之前的学习,我们知道如果自定义过滤器的使用。接下来,查看ruoyi源码,我们需要在过滤器中实现验证码。

前提

思路

1. Shiro的配置页面,添加自定义过滤器。过滤器需要传递两个参数:  captchaEnabled (验证码开关)和  captchaType  (验证码类型)。

2. 新建自定义过滤器,继承抽象类 AccessControlFilter 。在这里实现方法 isAccessAllowed (过滤前操作)(重点)和 onAccessDenied 验证失败后处理方法。我们把页面获取到的验证码和Session中得到的验证码进行对比。每次对比成功后,都要清除Session。

3. 新建绘制验证码并保存Session的接口。

4. 前端页面,添加验证码提交和验证码图片,用于提交时对比和绘制验证码。

步骤

1. 添加自定义过滤器。在配置文件(application.yml)添加两个参数 captchaEnabled (验证码开关)和 captchaType (验证码类型)。

1 # shiro配置
2 shiro:
3   user:
4     loginUrl: /login
5     captchaEnabled : true
6     captchaType: math

 

ShiroConfiguration.java 添加配置器的引用。

 1 /**
 2  * 验证码开关
 3  */
 4 @Value("${shiro.user.captchaEnabled}")
 5 private boolean captchaEnabled;
 6 
 7 /**
 8  * 验证码类型
 9  */
10 @Value("${shiro.user.captchaType}")
11 private String captchaType;

 

在拦截器添加登录页面的验证码接口

 过滤器方法如下:

 1 /**
 2  * 自定义验证码
 3  * @return
 4  */
 5 private Filter myCaptcha() {
 6     MyCaptchaFilter myCaptchaFilter = new MyCaptchaFilter();
 7     myCaptchaFilter.setCaptchaEnabled(captchaEnabled);
 8     myCaptchaFilter.setCaptchaType(captchaType);
 9     return myCaptchaFilter;
10 }

2. 自定义验证码过滤器,继承抽象类 AccessControlFilter 。添加接收参数的方法。

 1 /**
 2  * 验证码开关
 3  */
 4 private boolean captchaEnabled = true;
 5 
 6 /**
 7  * 验证码类型
 8  */
 9 private String captchaType= "math";
10 
11 public void setCaptchaEnabled(boolean captchaEnabled) {
12     this.captchaEnabled = captchaEnabled;
13 }
14 
15 public void setCaptchaType(String captchaType) {
16     this.captchaType = captchaType;
17 }

继承过滤前验证方法。当获取到的接口类型为“post”时且开启验证码时,进行验证,否则不进行验证。(验证方法,对比post请求的code和Session是否一致),返回true则放行下一个拦截器,返回false则执行 onAccessDenied 代码。

 1  @Override
 2 protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
 3     HttpServletRequest httpServletRequest = (HttpServletRequest) request;
 4     if(!captchaEnabled || !"post".equals(httpServletRequest.getMethod().toLowerCase())){
 5         return true;
 6     }
 7     return validateResponse(httpServletRequest, httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE));  //  public static final String CURRENT_VALIDATECODE = "validateCode";
 8 }
 9 
10 private boolean validateResponse(HttpServletRequest request, String validateCode) {
11     Object obj = ShiroUtils.getSession().getAttribute("KAPTCHA_SESSION_KEY");
12     String code = String.valueOf(obj != null ? obj : "");
13     System.out.println("code:"+code);
14     System.out.println("validateCode:"+validateCode);
15     // 验证码清除,防止多次使用。
16     request.getSession().removeAttribute("KAPTCHA_SESSION_KEY");
17     if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code))
18     {
19         return false;
20     }
21     return  true;
22 }

 验证后的处理方法。返回true则放行下一个拦截器,返回false,则不放行下一个拦截器。

1 @Override
2 protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
3     request.setAttribute(ShiroConstants.CURRENT_CAPTCHA, ShiroConstants.CAPTCHA_ERROR);//  request.setAttribute("captcha", "captchaError");
4     return false;
5 }

 3.新建绘制验证码并保存Session的接口。实际使用中,验证码的绘制可能更复杂,单独引用在其他地方。这里,简单引用随机生成N位数字的方式。使用BufferImage设置背景和每个字符。

 1 **
 2  * 图片验证码
 3  * 
 4  * @author ruoyi
 5  */
 6 @Controller
 7 @RequestMapping("/captcha")
 8 public class SysCaptchaController extends BaseController
 9 {
10     /**
11      * 页面验证码图片生成(并将图片存入session)
12      */
13     @GetMapping(value = "/captchaImage")
14     public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
15         int width = 120;
16         int height = 40;
17         BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
18         // 生成验证码
19         String code = generateCode(4);
20         // 绘制验证码
21         drawCaptcha(bufferedImage, code);
22         // 将验证码存入session
23         request.getSession().setAttribute("KAPTCHA_SESSION_KEY", code);
24         // 设置响应头
25         response.setContentType("image/jpeg");
26         response.setHeader("Pragma", "No-cache");
27         response.setHeader("Cache-Control", "no-cache");
28         response.setDateHeader("Expires", 0);
29         // 输出图片
30         ImageIO.write(bufferedImage,"jpg",response.getOutputStream());
31 
32         return  null;
33     }
34 
35     /**
36      * 生成验证码
37      * @param length
38      * @return
39      */
40     private String generateCode(int length){
41         Random random = new Random();
42         StringBuffer sb = new StringBuffer();
43         for (int i = 0; i < length; i++) {
44             sb.append(random.nextInt(10));
45         }
46         return sb.toString();
47     }
48 
49     /**
50      * 绘制验证码(可以自定义验证码的样式和细节)
51      * @param bufferedImage
52      * @param code
53      */
54     private void drawCaptcha(BufferedImage bufferedImage, String code) {
55         Graphics graphics = bufferedImage.getGraphics();
56         Random random = new Random();
57         // 设置背景
58         graphics.setColor(Color.WHITE);
59         graphics.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());
60         // 随机设置每个字符的颜色
61         for (int i = 0; i < code.length(); i++) {
62             Font font = new Font("Times New Roman", Font.BOLD, 30);
63             graphics.setColor(getColor(random));
64             graphics.setFont(font);
65             graphics.drawString(String.valueOf(code.charAt(i)), 30*i + 10, 30);
66         }
67 
68         graphics.dispose();
69     }
70 
71     // 字符随机颜色
72     private static Color getColor(Random random) {
73         return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
74     }
75 
76 }

4. 前端页面,添加验证码提交和验证码图片,用于提交时对比和绘制验证码。 Math.random() 用于生成随机数。src路径变化,则会调用后台接口,改变验证码。

1 <div  th:if="${captchaEnabled==true}">
2     <div >
3         验证码:<input type="text" name="validateCode" placeholder="验证码" maxlength="5" />
4     </div>
5     <div >
6         <img th:src="/captcha/captchaImage"  title="点击刷新验证码" width="120" height="40" onclick="this.src='/captcha/captchaImage?'+Math.random()" />
7     </div>
8 </div>

 

posted @ 2024-10-25 09:25  陆陆无为而治者  阅读(9)  评论(0编辑  收藏  举报