最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Security實(shí)現(xiàn)驗(yàn)證碼登錄功能

 更新時(shí)間:2020年01月15日 09:39:35   作者:炫舞風(fēng)中  
這篇文章主要介紹了Spring Security實(shí)現(xiàn)驗(yàn)證碼登錄功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了Spring Security實(shí)現(xiàn)驗(yàn)證碼登錄功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

spring security實(shí)現(xiàn)登錄注銷功能的基礎(chǔ)上進(jìn)行開發(fā)。

1、添加生成驗(yàn)證碼的控制器。

(1)、生成驗(yàn)證碼

/**
   * 引入 Security 配置屬性類
   */
  @Autowired
  private SecurityProperties securityProperties;


  @Override
  public ImageCode createCode(HttpServletRequest request ) {
    //如果請求中有 width 參數(shù),則用請求中的,否則用 配置屬性中的
    int width = ServletRequestUtils.getIntParameter(request,"width",securityProperties.getWidth());
    //高度(寬度)
    int height = ServletRequestUtils.getIntParameter(request,"height",securityProperties.getHeight());
    //圖片驗(yàn)證碼字符個(gè)數(shù)
    int length = securityProperties.getLength();
    //過期時(shí)間
    int expireIn = securityProperties.getExpireIn();

    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 < length; 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, expireIn);
  }

  /**
   * 生成隨機(jī)背景條紋
   */
  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);
  }

(2)、驗(yàn)證碼控制器

public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE";

  @Autowired
  private ValidateCodeGenerator imageCodeGenerator;

  /**
   * Session 對象
   */
  private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

  @GetMapping("/code/image")
  public void createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    ImageCode imageCode = imageCodeGenerator.createCode(request);
    //將隨機(jī)數(shù) 放到Session中
    sessionStrategy.setAttribute(new ServletWebRequest(request),SESSION_KEY,imageCode);
    request.getSession().setAttribute(SESSION_KEY,imageCode);
    //寫給response 響應(yīng)
    response.setHeader("Cache-Control", "no-store, no-cache");
    response.setContentType("image/jpeg");
    ImageIO.write(imageCode.getImage(),"JPEG",response.getOutputStream());
  }

(3)、其它輔助類

@Data
public class ImageCode {

  /**
   * 圖片
   */
  private BufferedImage image;
  /**
   * 隨機(jī)數(shù)
   */
  private String code;
  /**
   * 過期時(shí)間
   */
  private LocalDateTime expireTime;

  public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
    this.image = image;
    this.code = code;
    this.expireTime = expireTime;
  }
  public ImageCode(BufferedImage image, String code, int expireIn) {
    this.image = image;
    this.code = code;
    //當(dāng)前時(shí)間 加上 設(shè)置過期的時(shí)間
    this.expireTime = LocalDateTime.now().plusSeconds(expireIn);
  }

  public boolean isExpried(){
    //如果 過期時(shí)間 在 當(dāng)前日期 之前,則驗(yàn)證碼過期
    return LocalDateTime.now().isAfter(expireTime);
  }
}
@ConfigurationProperties(prefix = "sso.security.code.image")
@Component
@Data
public class SecurityProperties {

  /**
   * 驗(yàn)證碼寬度
   */
  private int width = 67;
  /**
   * 高度
   */
  private int height = 23;
  /**
   * 長度(幾個(gè)數(shù)字)
   */
  private int length = 4;
  /**
   * 過期時(shí)間
   */
  private int expireIn = 60;

  /**
   * 需要圖形驗(yàn)證碼的 url
   */
  private String url;
}

(4)、驗(yàn)證

2、添加過濾器,進(jìn)行驗(yàn)證碼驗(yàn)證

@Component
@Slf4j
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean {

  /**
   * 登錄失敗處理器
   */
  @Autowired
  private AuthenticationFailureHandler failureHandler;
  /**
   * Session 對象
   */
  private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

  /**
   * 創(chuàng)建一個(gè)Set 集合 存放 需要驗(yàn)證碼的 urls
   */
  private Set<String> urls = new HashSet<>();
  /**
   * spring的一個(gè)工具類:用來判斷 兩字符串 是否匹配
   */
  private AntPathMatcher pathMatcher = new AntPathMatcher();

  @Autowired
  private SecurityProperties securityProperties;
  /**
   * 這個(gè)方法是 InitializingBean 接口下的一個(gè)方法, 在初始化配置完成后 運(yùn)行此方法
   */
  @Override
  public void afterPropertiesSet() throws ServletException {
    super.afterPropertiesSet();
    //將 application 配置中的 url 屬性進(jìn)行 切割
    String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getUrl(), ",");
    //添加到 Set 集合里
    urls.addAll(Arrays.asList(configUrls));
    //因?yàn)榈卿浾埱笠欢ㄒ序?yàn)證碼 ,所以直接 add 到set 集合中
    urls.add("/authentication/form");
  }

  @Override
  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

    boolean action = false;
    for (String url:urls){
      //如果請求的url 和 配置中的url 相匹配
      if (pathMatcher.match(url,httpServletRequest.getRequestURI())){
        action = true;
      }
    }

    //攔截請求
    if (action){
      logger.info("攔截成功"+httpServletRequest.getRequestURI());
      //如果是登錄請求
      try {
        validate(new ServletWebRequest(httpServletRequest));
      }catch (ValidateCodeException exception){
        //返回錯(cuò)誤信息給 失敗處理器
        failureHandler.onAuthenticationFailure(httpServletRequest,httpServletResponse,exception);
        return;
      }

    }
    filterChain.doFilter(httpServletRequest,httpServletResponse);

  }
  private void validate(ServletWebRequest request) throws ServletRequestBindingException {
    //從session中取出 驗(yàn)證碼
    ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(request,ValidateCodeController.SESSION_KEY);
    //從request 請求中 取出 驗(yàn)證碼
    String codeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(),"imageCode");

    if (StringUtils.isBlank(codeInRequest)){
      logger.info("驗(yàn)證碼不能為空");
      throw new ValidateCodeException("驗(yàn)證碼不能為空");
    }
    if (codeInSession == null){
      logger.info("驗(yàn)證碼不存在");
      throw new ValidateCodeException("驗(yàn)證碼不存在");
    }
    if (codeInSession.isExpried()){
      logger.info("驗(yàn)證碼已過期");
      sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
      throw new ValidateCodeException("驗(yàn)證碼已過期");
    }
    if (!StringUtils.equals(codeInSession.getCode(),codeInRequest)){
      logger.info("驗(yàn)證碼不匹配"+"codeInSession:"+codeInSession.getCode() +", codeInRequest:"+codeInRequest);
      throw new ValidateCodeException("驗(yàn)證碼不匹配");
    }
    //把對應(yīng) 的 session信息 刪掉
    sessionStrategy.removeAttribute(request,ValidateCodeController.SESSION_KEY);
  }

3、在核心配置BrowserSecurityConfig中添加過濾器配置

@Autowired
  private ValidateCodeFilter validateCodeFilter;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    //在UsernamePasswordAuthenticationFilter 過濾器前 加一個(gè)過濾器 來搞驗(yàn)證碼
    http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
        //表單登錄 方式
        .formLogin()
        .loginPage("/authentication/require")
        //登錄需要經(jīng)過的url請求
        .loginProcessingUrl("/authentication/form")
        .passwordParameter("pwd")
        .usernameParameter("user")
        .successHandler(mySuccessHandler)
        .failureHandler(myFailHandler)
        .and()
        //請求授權(quán)
        .authorizeRequests()
        //不需要權(quán)限認(rèn)證的url
        .antMatchers("/authentication/*","/code/image").permitAll()
        //任何請求
        .anyRequest()
        //需要身份認(rèn)證
        .authenticated()
        .and()
        //關(guān)閉跨站請求防護(hù)
        .csrf().disable();
    //默認(rèn)注銷地址:/logout
    http.logout().
        //注銷之后 跳轉(zhuǎn)的頁面
        logoutSuccessUrl("/authentication/require");
  }

4、異常輔助類

public class ValidateCodeException extends AuthenticationException {
  public ValidateCodeException(String msg, Throwable t) {
    super(msg, t);
  }

  public ValidateCodeException(String msg) {
    super(msg);
  }
}

5、測試

(1)、不輸入驗(yàn)證碼

(2)、添加驗(yàn)證碼

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring boot 集成 Druid 數(shù)據(jù)源過程詳解

    Spring boot 集成 Druid 數(shù)據(jù)源過程詳解

    這篇文章主要介紹了Spring boot 集成 Druid 數(shù)據(jù)源過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Spring使用Jackson實(shí)現(xiàn)轉(zhuǎn)換XML與Java對象

    Spring使用Jackson實(shí)現(xiàn)轉(zhuǎn)換XML與Java對象

    這篇文章主要為大家詳細(xì)介紹了Spring如何使用Jackson實(shí)現(xiàn)轉(zhuǎn)換XML與Java對象,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • 使用BindingResult 自定義錯(cuò)誤信息

    使用BindingResult 自定義錯(cuò)誤信息

    這篇文章主要介紹了使用BindingResult 自定義錯(cuò)誤信息,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java線程池源碼的深度解析

    Java線程池源碼的深度解析

    線程池的好處和使用本篇文章就不贅敘了,這篇文章主要通過線程池的源碼帶大家深入了解一下jdk8中線程池的實(shí)現(xiàn),感興趣的小伙伴可以了解一下
    2022-10-10
  • jackson json序列化實(shí)現(xiàn)首字母大寫,第二個(gè)字母需小寫

    jackson json序列化實(shí)現(xiàn)首字母大寫,第二個(gè)字母需小寫

    這篇文章主要介紹了jackson json序列化實(shí)現(xiàn)首字母大寫,第二個(gè)字母需小寫方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringShell命令行之交互式Shell應(yīng)用開發(fā)方式

    SpringShell命令行之交互式Shell應(yīng)用開發(fā)方式

    本文將深入探討Spring Shell的核心特性、實(shí)現(xiàn)方式及應(yīng)用場景,幫助開發(fā)者掌握這一強(qiáng)大工具,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java枚舉類型與泛型使用解讀

    Java枚舉類型與泛型使用解讀

    這篇文章主要介紹了Java枚舉類型與泛型使用解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Spring Boot 中的 @PutMapping 注解原理及使用小結(jié)

    Spring Boot 中的 @PutMapping 注解原理及使用小結(jié)

    在本文中,我們介紹了 Spring Boot 中的 @PutMapping 注解,它可以將 HTTP PUT 請求映射到指定的處理方法上,我們還介紹了 @PutMapping 注解的原理以及如何在 Spring Boot 中使用它,感興趣的朋友跟隨小編一起看看吧
    2023-12-12
  • 為何Java單例模式我只推薦兩種

    為何Java單例模式我只推薦兩種

    這篇文章主要給大家介紹了關(guān)于Java單例模式推薦的兩種模式,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • sprng和struts有什么區(qū)別?

    sprng和struts有什么區(qū)別?

    Spring和Struts都是近年來比較流行的框架,Struts主要用于表示層,Spring用于業(yè)務(wù)層,以及Hiberate主要用于持久層,
    2015-06-06

最新評論

周口市| 玉树县| 闽清县| 临武县| 东兰县| 中江县| 蕉岭县| 涡阳县| 绵竹市| 布尔津县| 遵义县| 大安市| 仙桃市| 潼南县| 黑水县| 揭阳市| 嘉峪关市| 手机| 凭祥市| 德阳市| 定南县| 正镶白旗| 土默特左旗| 沧州市| 米易县| 石门县| 社会| 会宁县| 唐海县| 五台县| 凤冈县| 都昌县| 巴林右旗| 榕江县| 南和县| 南靖县| 高陵县| 沾化县| 崇文区| 简阳市| 祥云县|