一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

2022-01-19 01:02一一哥Sun Java教程

這篇文章主要介紹了Spring Security基于自定義的認證提供器實現圖形驗證碼,通過本文學習下AuthenticationProvider接口的類關系圖,感興趣的朋友跟隨小編一起看看吧

前言

在上一個章節中,一一哥 帶大家實現了如何在Spring Security中添加執行自定義的過濾器,進而實現驗證碼校驗功能這種實現方式,只是實現驗證碼功能的方式之一,接下來我們再學習另一種實現方式,就是利用AuthenticationProver來實現驗證碼功能,通過這個案例,我們學習如何進行自定義AuthenticationProver。

 

一. 認證提供器簡介

在上一章節中,我帶各位利用自定義的過濾器實現了圖形驗證碼效果,接下來我們利用另一種方式,基于自定義的認證提供器來實現圖形驗證碼。

1. 認證提供器AuthenticationProver

在第11章節中,壹哥 給大家講過Spring Security的認證授權實現流程,其中就給大家講解過AuthenticationProver的作用,接下來我們看一下AuthenticationProver接口的類關系圖:

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

從上圖中可知,AuthenticationProver是一個接口,該接口有一個直接的子類AbstractUserDetailsAuthenticationProver,該類有2個抽象的方法:additionalAuthenticationChecks() 和 retrieveUser(),如下圖:

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

我們可以通過編寫一個子類繼承AbstractUserDetailsAuthenticationProver,復寫這2個抽象方法,進行滿足自己需求的擴展實現。Spring Security中的DaoAuthenticationProver子類就是通過復寫這2個抽象方法,實現了基于數據庫模型的認證授權。

我們今天會通過繼承DaoAuthenticationProver,來實現圖形驗證碼的校驗功能。

2. WebAuthenticationDetails類介紹

了解完上面的AuthenticationProver類之后,我們還需要了解另一個類WebAuthenticationDetails。

我們知道在Spring Security中有一個UsernamePasswordAuthenticationToken類,封裝了用戶的principal、credentials信息,該類還從它的父類AbstractAuthenticationToken中繼承了details信息。其中這個details信息表示認證用戶的額外信息,比如請求用戶的remoteAddress和sessionId等信息,這兩個信息都是在另一個WebAuthenticationDetails類中定義的,所以我們可以利用WebAuthenticationDetails來封裝用戶的額外信息。

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

了解完上面的這些必要的API,我們就可以實現今天的需求了。

 

二. 實現圖形驗證碼

1. 添加依賴包

我們還是和之前的案例一樣,可以先創建一個新的module,創建過程略。

在本案例中我們依然采用github上的開源驗證碼解決方案kaptcha,所以需要在原有項目的基礎上添加kaptcha的依賴包。

<dependencies>
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
      </dependency>

      <dependency>
          <groupId>org.mybatis.spring.boot</groupId>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <version>1.3.1</version>
      </dependency>

      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <scope>runtime</scope>
      </dependency>

      <dependency>
          <groupId>com.github.penggle</groupId>
          <artifactId>kaptcha</artifactId>
          <version>2.3.2</version>
      </dependency>

      <dependency>
          <groupId>org.springframework.security</groupId>
          <artifactId>spring-security-test</artifactId>
          <scope>test</scope>
      </dependency>
  </dependencies>

2. 創建Producer對象

跟上一個案例一樣,創建CaptchaConfig配置類,在該類中創建一個Producer對象,對驗證碼對象進行必要的配置。

@Configuration
public class CaptchaConfig {

  @Bean
  public Producer captcha() {
      // 配置圖形驗證碼的基本參數
      Properties properties = new Properties();
      // 圖片寬度
      properties.setProperty("kaptcha.image.wth", "150");
      // 圖片長度
      properties.setProperty("kaptcha.image.height", "50");
      // 字符集
      properties.setProperty("kaptcha.textproducer.char.string", "0123456789");
      // 字符長度
      properties.setProperty("kaptcha.textproducer.char.length", "4");
      Config config = new Config(properties);
      // 使用默認的圖形驗證碼實現,當然也可以自定義實現
      DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
      defaultKaptcha.setConfig(config);
      return defaultKaptcha;
  }

}

3. 創建生成驗證碼的接口

在上面創建了Producer對象后,接著創建一個生成驗證碼的接口,該接口中負責生成驗證碼圖片,并將驗證碼存儲到session中。

@Controller
public class CaptchaController {

  @Autowired
  private Producer captchaProducer;

  @GetMapping("/captcha.jpg")
  public vo getCaptcha(HttpServletRequest request, HttpServletResponse response) throws IOException {
      // 設置內容類型
      response.setContentType("image/jpeg");
      // 創建驗證碼文本
      String capText = captchaProducer.createText();
      
      // 將驗證碼文本設置到session
      request.getSession().setAttribute("captcha", capText);
      
      // 創建驗證碼圖片
      BufferedImage bi = captchaProducer.createImage(capText);
      // 獲取響應輸出流
      ServletOutputStream out = response.getOutputStream();
      // 將圖片驗證碼數據寫到響應輸出流
      ImageIO.write(bi, "jpg", out);
      
      // 推送并關閉響應輸出流
      try {
          out.flush();
      } finally {
          out.close();
      }
  }

}

4. 自定義異常

接下來自定義一個運行時異常,用于處理驗證碼校驗失敗時拋出異常提示信息。

public class VerificationCodeException extends AuthenticationException {

  public VerificationCodeException() {
      super("圖形驗證碼校驗失敗");
  }

}

5. 自定義WebAuthenticationDetails

我在上面給大家介紹過WebAuthenticationDetails這個類,知道該類中可以封裝用戶的額外信息,所以在這里我們自定義一個WebAuthenticationDetails類,封裝驗證碼信息,并把用戶傳遞過來的驗證碼與session中保存的驗證碼進行對比。

/**
* 添加額外的用戶認證信息
*/  
public class MyWebAuthenticationDetails extends WebAuthenticationDetails {

  private String imageCode;

  private String savedImageCode;

  public String getImageCode() {
      return imageCode;
  }

  public String getSavedImageCode() {
      return savedImageCode;
  }

  /**
   * 補充用戶提交的驗證碼和session保存的驗證碼
   */  
  public MyWebAuthenticationDetails(HttpServletRequest request) {
      super(request);
      this.imageCode = request.getParameter("captcha");
      //獲取session對象
      HttpSession session = request.getSession();
      
      this.savedImageCode = (String) session.getAttribute("captcha");
      if (!StringUtils.isEmpty(this.savedImageCode)) {
          // 隨手清除驗證碼,不管是失敗還是成功,所以客戶端應在登錄失敗時刷新驗證碼
          session.removeAttribute("captcha");
      }
  }

}

6. 自定義AuthenticationDetailsSource

AuthenticationDetailsSource是一個接口,該接口帶有一個buildDetails方法,該方法會在創建一個新的authentication的details對象時被調用,而且可以在這里傳遞給details對象一個request參數,如下圖所示:

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

所以這里我們定義一個AuthenticationDetailsSource類,通過該類構建出上面定義的WebAuthenticationDetails對象,并且給WebAuthenticationDetails傳遞進去HttpServletRequest對象。

@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails> {

  /**
   * 創建一個WebAuthenticationDetails對象
   */  
  @Overre
  public WebAuthenticationDetails buildDetails(HttpServletRequest request) {

      return new MyWebAuthenticationDetails(request);
  }

}

7. 自定義DaoAuthenticationProver

接下來通過繼承DaoAuthenticationProver父類,來引入對圖形驗證碼的驗證操作。

/**
* 在常規的數據庫認證之上,添加圖形驗證碼功能
*/
@Component
public class MyAuthenticationProver extends DaoAuthenticationProver {

  /**
   * 構造方法注入UserDetailService和PasswordEncoder
   */
  public MyAuthenticationProver(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
      this.setUserDetailsService(userDetailsService);
      this.setPasswordEncoder(passwordEncoder);
  }

  /**
   * 在常規的認證之上,添加額外的圖形驗證碼功能
   */
  @Overre
  protected vo additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
      //獲取token令牌中關聯的details對象,并將其轉換為我們自定義的MyWebAuthenticationDetails
      MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) usernamePasswordAuthenticationToken.getDetails();
      String imageCode = details.getImageCode();
      String savedImageCode = details.getSavedImageCode();
      
      // 檢驗圖形驗證碼
      if (StringUtils.isEmpty(imageCode) || StringUtils.isEmpty(savedImageCode) || !imageCode.equals(savedImageCode)) {
          throw new VerificationCodeException();
      }

      //在正常的認證檢查之前,添加額外的關于圖形驗證碼的校驗
      super.additionalAuthenticationChecks(userDetails, usernamePasswordAuthenticationToken);
  }

}

8. 添加SecurityConfig

然后創建編寫SecurityConfig類,關聯配置我們前面編寫的AuthenticationDetailsSource和AuthenticationProver類。

@SuppressWarnings("all")
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> myWebAuthenticationDetailsSource;

  @Autowired
  private AuthenticationProver authenticationProver;

  @Overre
  protected vo configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
              .antMatchers("/admin/api/**")
              .hasRole("ADMIN")
              .antMatchers("/user/api/**")
              .hasRole("USER")
              .antMatchers("/app/api/**", "/captcha.jpg")
              .permitAll()
              .anyRequest()
              .authenticated()
              .and()
              .formLogin()
          	//這里關聯配置自定義的AuthenticationDetailsSource
              .authenticationDetailsSource(myWebAuthenticationDetailsSource)
              .failureHandler(new SecurityAuthenticationFailureHandler())
              .successHandler(new SecurityAuthenticationSuccessHandler())
              .loginPage("/myLogin.html")
              .loginProcessingUrl("/login")
              .permitAll()
              .and()
              .csrf()
              .disable();
  }

  //在這里關聯我們自定義的AuthenticationProver
  @Overre
  protected vo configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.authenticationProver(authenticationProver);
  }

  @Bean
  public PasswordEncoder passwordEncoder() {

      return NoOpPasswordEncoder.getInstance();
  }

}

9. 編寫測試頁面

最后編寫一個自定義的登錄頁面,在這里添加對驗證碼接口的引用,我這里列出html的核心代碼。

<body>
      <div class="login">
          <h2>Access Form</h2>
          <div class="login-top">
              <h1>登錄驗證</h1>
              <form action="/login" method="post">
                  <input type="text" name="username" placeholder="username" />
                  <input type="password" name="password" placeholder="password" />
                  <div style="display: flex;">
                      <!-- 新增圖形驗證碼的輸入框 -->
                      <input type="text" name="captcha" placeholder="captcha" />
                      <!-- 圖片指向圖形驗證碼API -->
                      <img src="/captcha.jpg"                  </div>
                  <div class="forgot">
                      <a href="#" rel="external nofollow"  rel="external nofollow" >忘記密碼</a>
                      <input type="submit" value="登錄" >
                  </div>
              </form>
          </div>
          <div class="login-bottom">
              <h3>新用戶&nbsp;<a href="#" rel="external nofollow"  rel="external nofollow" >注&nbsp;冊</a></h3>
          </div>
      </div>
  </body>

10. 代碼結構

本案例的主要代碼結構如下圖所示,各位可以參考創建。

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

11. 啟動項目測試

接下來我們啟動項目,跳轉到登錄頁面后,我們就可以看到驗證碼已經被創建出來了。

Spring Security基于自定義的認證提供器實現圖形驗證碼流程解析

此時我們可以看到生成的數字驗證碼,在我們輸入正確的用戶名、密碼、驗證碼后,就可以成功的登錄進去訪問web接口了。

至此,我們就實現了基于自定義的認證提供器來實現圖形驗證碼功能了,這種實現方式要比第一種實現方式更復雜一些,其實都能滿足我們的開發需求。有的小伙伴會問,開發時到底選擇哪一種方式呢?壹哥覺得都無所謂的!你有什么更好的見解嗎?可以在評論區留言哦!

到此這篇關于Spring Security基于自定義的認證提供器實現圖形驗證碼的文章就介紹到這了,更多相關Spring Security認證提供器實現圖形驗證碼內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/syc000666/article/details/120481562

延伸 · 閱讀

精彩推薦
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
主站蜘蛛池模板: 俄罗斯处女 | 好吊色视频988gao在线观看 | 45分钟做受片免费观看 | 欧美 变态 另类 人妖班 | 亚洲天堂精品视频 | 成在线人免费视频一区二区三区 | www免费视频com | 艾秋麻豆果冻传媒老狼仙踪林 | 欧美乱子伦xxxx12在线 | 亚洲高清中文字幕 | 欧美日韩国产在线人成 | 午夜精品国产 | ai换脸杨颖啪啪免费网站 | 四虎2023| 国产一卡二卡3卡4卡更新 | 午夜神器老司机高清无码 | 日韩精品在线一区二区 | 日日夜夜撸影院 | 三体动漫在线观看免费完整版2022 | 久久草福利自拍视频在线观看 | 国产精亚洲视频 | 美女视频久久 | 校花被老头夺去第一次动图 | 青青青青在线视频 | 777奇米影视一区二区三区 | 手机在线观看精品国产片 | 万域之王在线观看 | 亚洲婷婷在线视频 | 99年水嫩漂亮粉嫩在线播放 | 好男人资源免费播放 | 亚洲成在人线视频 | 免费高清在线 | 亚洲第一男人网站 | 亚洲男人天堂网站 | 亚洲天堂网在线观看视频 | 户外露出野战hd | 粉嫩高中生第一次不戴套 | 国产成人看片免费视频观看 | 成人依依网 | 俄罗斯年轻男同gay69 | 免费看欧美一级特黄a大片一 |