• 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 }
  • 相关阅读:
    Java学习笔记12---向上转型-父类的对象引用指向子类对象
    Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序
    Java学习笔记10---访问权限修饰符如何控制成员变量、成员方法及类的访问范围
    Java学习笔记9---类静态成员变量的存储位置及JVM的内存划分
    Java学习笔记8---类的静态成员变量与静态成员方法的访问与调用方式
    Java学习笔记7---父类构造方法有无参数对子类的影响
    Java学习笔记6---字符串比较方法compareTo(String str)
    地址总线、数据总线、寻址能力、字长及cpu位数等概念之间的关系
    Alpha事后诸葛亮
    第05组 Alpha冲刺(4/4)
  • 原文地址:https://www.cnblogs.com/fanqisoft/p/10630556.html
Copyright © 2020-2023  润新知