zoukankan      html  css  js  c++  java
  • SpringSecurity实现图形验证码功能

    ⒈封装验证码类

     1 package cn.coreqi.security.validate;
     2 
     3 import java.awt.image.BufferedImage;
     4 import java.time.LocalDateTime;
     5 
     6 public class ImageCode {
     7     private BufferedImage image;
     8     private String code;
     9     private LocalDateTime expireTime;   //过期时间
    10 
    11     public ImageCode(BufferedImage image, String code, Integer expireIn) {
    12         this.image = image;
    13         this.code = code;
    14         this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
    15     }
    16 
    17     public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
    18         this.image = image;
    19         this.code = code;
    20         this.expireTime = expireTime;
    21     }
    22 
    23     public boolean isExpried(){
    24         return LocalDateTime.now().isAfter(expireTime);
    25     }
    26 
    27     public BufferedImage getImage() {
    28         return image;
    29     }
    30 
    31     public void setImage(BufferedImage image) {
    32         this.image = image;
    33     }
    34 
    35     public String getCode() {
    36         return code;
    37     }
    38 
    39     public void setCode(String code) {
    40         this.code = code;
    41     }
    42 
    43     public LocalDateTime getExpireTime() {
    44         return expireTime;
    45     }
    46 
    47     public void setExpireTime(LocalDateTime expireTime) {
    48         this.expireTime = expireTime;
    49     }
    50 }

    ⒉封装验证码控制器

     1 package cn.coreqi.security.controller;
     2 
     3 import cn.coreqi.security.validate.ImageCode;
     4 import com.sun.image.codec.jpeg.JPEGCodec;
     5 import com.sun.image.codec.jpeg.JPEGImageEncoder;
     6 import org.springframework.social.connect.web.HttpSessionSessionStrategy;
     7 import org.springframework.social.connect.web.SessionStrategy;
     8 import org.springframework.web.bind.annotation.GetMapping;
     9 import org.springframework.web.bind.annotation.RestController;
    10 import org.springframework.web.context.request.ServletWebRequest;
    11 
    12 import javax.imageio.ImageIO;
    13 import javax.servlet.http.HttpServletRequest;
    14 import javax.servlet.http.HttpServletResponse;
    15 import java.awt.*;
    16 import java.awt.image.BufferedImage;
    17 import java.io.IOException;
    18 import java.util.Random;
    19 
    20 @RestController
    21 public class ValidateController {
    22 
    23     public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";
    24     private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    25 
    26     @GetMapping("code/image")
    27     public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    28         ImageCode imageCode = createImageCode(request);
    29         sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode);
    30         
    31         response.setHeader("Pragma","No-cache");
    32         response.setHeader("Cache-Control","no-cache");
    33         //response.setDateHeader("Expires", 0);
    34         
    35         JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(response.getOutputStream());
    36         encoder.encode(imageCode.getImage());
    37         
    38         //ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());    //当tomcat下temp文件夹不存在则"Can't create output stream"
    39     }
    40 
    41     private ImageCode createImageCode(HttpServletRequest request) {
    42         int width = 67;
    43         int height = 23;
    44         BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
    45 
    46         Graphics g = image.getGraphics();
    47 
    48         Random random = new Random();
    49 
    50         g.setColor(getRandColor(200,250));
    51         g.fillRect(0,0,width,height);
    52         g.setFont(new Font("Times New Roman",Font.ITALIC,20));
    53         g.setColor(getRandColor(160,200));
    54         for (int i = 0;i < 155; i++){
    55             int x = random.nextInt(width);
    56             int y = random.nextInt(height);
    57             int xl = random.nextInt(12);
    58             int yl = random.nextInt(12);
    59             g.drawLine(x,y,x+xl,y+yl);
    60         }
    61         String sRand = "";
    62         for(int i = 0;i < 4; i++){
    63             String rand = String.valueOf(random.nextInt(10));
    64             sRand += rand;
    65             g.setColor(new Color(20 + random.nextInt(110),20 + random.nextInt(110),20 + random.nextInt(110)));
    66             g.drawString(rand,13 * i + 6,16);
    67         }
    68         g.dispose();
    69         return new ImageCode(image,sRand,60);
    70     }
    71 
    72     /**
    73      * 生成随机背景条纹
    74      * @param fc
    75      * @param bc
    76      * @return
    77      */
    78     private Color getRandColor(int fc, int bc) {
    79         Random random = new Random();
    80         if(fc > 255){
    81             fc = 255;
    82         }
    83         if(bc > 255){
    84             bc = 255;
    85         }
    86         int r = fc + random.nextInt(bc - fc);
    87         int g = fc + random.nextInt(bc - fc);
    88         int b = fc + random.nextInt(bc - fc);
    89         return new Color(r,g,b);
    90     }
    91 }

    ⒊放行验证码的Rest地址

    ⒋表单添加验证码

    1             <tr>
    2                 <td>图形验证码:</td>
    3                 <td>
    4                     <input type="text" name="imageCode">
    5                     <img src="/code/image">
    6                 </td>
    7             </tr>

    ⒌声明一个验证码异常,用于抛出特定的验证码异常

    1 package cn.coreqi.security.validate;
    2 
    3 import org.springframework.security.core.AuthenticationException;
    4 
    5 public class ValidateCodeException extends AuthenticationException {
    6     public ValidateCodeException(String msg) {
    7         super(msg);
    8     }
    9 }

    ⒍创建一个过滤器,用于验证请求中的验证码是否正确

     1 package cn.coreqi.security.Filter;
     2 
     3 import cn.coreqi.security.validate.ImageCode;
     4 import cn.coreqi.security.validate.ValidateCodeException;
     5 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
     6 import org.springframework.social.connect.web.HttpSessionSessionStrategy;
     7 import org.springframework.social.connect.web.SessionStrategy;
     8 import org.springframework.util.StringUtils;
     9 import org.springframework.web.bind.ServletRequestBindingException;
    10 import org.springframework.web.bind.ServletRequestUtils;
    11 import org.springframework.web.context.request.ServletWebRequest;
    12 import org.springframework.web.filter.OncePerRequestFilter;
    13 import cn.coreqi.security.controller.*;
    14 
    15 import javax.servlet.FilterChain;
    16 import javax.servlet.ServletException;
    17 import javax.servlet.http.HttpServletRequest;
    18 import javax.servlet.http.HttpServletResponse;
    19 import java.io.IOException;
    20 
    21 public class ValidateCodeFilter extends OncePerRequestFilter {
    22 
    23     private AuthenticationFailureHandler authenticationFailureHandler;
    24 
    25     private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
    26 
    27     public AuthenticationFailureHandler getAuthenticationFailureHandler() {
    28         return authenticationFailureHandler;
    29     }
    30 
    31     public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
    32         this.authenticationFailureHandler = authenticationFailureHandler;
    33     }
    34 
    35     public SessionStrategy getSessionStrategy() {
    36         return sessionStrategy;
    37     }
    38 
    39     public void setSessionStrategy(SessionStrategy sessionStrategy) {
    40         this.sessionStrategy = sessionStrategy;
    41     }
    42 
    43     @Override
    44     protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
    45         if (httpServletRequest.equals("/authentication/form") && httpServletRequest.getMethod().equals("post")) {
    46             try {
    47                 validate(new ServletWebRequest(httpServletRequest));
    48 
    49             }catch (ValidateCodeException e){
    50                 authenticationFailureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,e);
    51                 return;
    52             }
    53         }
    54         filterChain.doFilter(httpServletRequest,httpServletResponse);   //如果不是登录请求,直接调用后面的过滤器链
    55     }
    56 
    57     private void validate(ServletWebRequest request) throws ServletRequestBindingException {
    58         ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request,ValidateController.SESSION_KEY);
    59         String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"imageCode");
    60         if(!StringUtils.hasText(codeInRequest)){
    61             throw new ValidateCodeException("验证码的值不能为空!");
    62         }
    63         if(codeInSession == null){
    64             throw new ValidateCodeException("验证码不存在!");
    65         }
    66         if(codeInSession.isExpried()){
    67             sessionStrategy.removeAttribute(request,ValidateController.SESSION_KEY);
    68             throw new ValidateCodeException("验证码已过期!");
    69         }
    70         if(!codeInSession.getCode().equals(codeInRequest)){
    71             throw new ValidateCodeException("验证码不正确!");
    72         }
    73         sessionStrategy.removeAttribute(request,ValidateController.SESSION_KEY);
    74     }
    75 }

    ⒎在SpringSecurity过滤器链中注册我们的过滤器

     1 package cn.coreqi.security.config;
     2 
     3 import cn.coreqi.security.Filter.ValidateCodeFilter;
     4 import org.springframework.beans.factory.annotation.Autowired;
     5 import org.springframework.context.annotation.Bean;
     6 import org.springframework.context.annotation.Configuration;
     7 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
     8 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
     9 import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    10 import org.springframework.security.crypto.password.PasswordEncoder;
    11 import org.springframework.security.web.authentication.AuthenticationFailureHandler;
    12 import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
    13 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    14 
    15 @Configuration
    16 public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    17 
    18     @Autowired
    19     private AuthenticationSuccessHandler coreqiAuthenticationSuccessHandler;
    20 
    21     @Autowired
    22     private AuthenticationFailureHandler coreqiAuthenticationFailureHandler;
    23 
    24     @Bean
    25     public PasswordEncoder passwordEncoder(){
    26         return NoOpPasswordEncoder.getInstance();
    27     }
    28 
    29     @Override
    30     protected void configure(HttpSecurity http) throws Exception {
    31         ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
    32         validateCodeFilter.setAuthenticationFailureHandler(coreqiAuthenticationFailureHandler);
    33 
    34         //http.httpBasic()    //httpBasic登录 BasicAuthenticationFilter
    35         http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)    //加载用户名密码过滤器的前面
    36                 .formLogin()    //表单登录 UsernamePasswordAuthenticationFilter
    37                 .loginPage("/coreqi-signIn.html")  //指定登录页面
    38                 //.loginPage("/authentication/require")
    39                 .loginProcessingUrl("/authentication/form") //指定表单提交的地址用于替换UsernamePasswordAuthenticationFilter默认的提交地址
    40                 .successHandler(coreqiAuthenticationSuccessHandler) //登录成功以后要用我们自定义的登录成功处理器,不用Spring默认的。
    41                 .failureHandler(coreqiAuthenticationFailureHandler) //自己体会把
    42                 .and()
    43                 .authorizeRequests()    //对授权请求进行配置
    44                 .antMatchers("/coreqi-signIn.html","/code/image").permitAll() //指定登录页面不需要身份认证
    45                 .anyRequest().authenticated()  //任何请求都需要身份认证
    46                 .and().csrf().disable();    //禁用CSRF
    47             //FilterSecurityInterceptor 整个SpringSecurity过滤器链的最后一环
    48     }
    49 }
  • 相关阅读:
    Android开发总结
    LeakCanary原理分析
    机器学习
    Kivy 中文教程 实例入门 简易画板 (Simple Paint App):2. 实现绘图功能
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 3. 循环
    Kivy 中文教程 实例入门 简易画板 (Simple Paint App):1. 自定义窗口部件 (widget)
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 2. 变量
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 1. 神秘朋友
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 0. 准备工作
    远程显示(操作) 服务器 GUI 程序(图形化界面) (基于 X11 Forwarding + Centos + MobaXterm)
  • 原文地址:https://www.cnblogs.com/fanqisoft/p/10630556.html
Copyright © 2011-2022 走看看