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

Spring Security基于過濾器實現(xiàn)圖形驗證碼功能

 更新時間:2021年09月26日 11:16:40   作者:一一哥Sun  
驗證碼就是為了防止惡意用戶采用暴力重試的攻擊手段而設(shè)置的一種防護措施,接下來在Spring Security的環(huán)境中,我們可以用兩種方案實現(xiàn)圖形驗證碼,具體實現(xiàn)方法跟隨小編一起看看吧

前言

在前兩個章節(jié)中,一一哥 帶大家學(xué)習(xí)了Spring Security內(nèi)部關(guān)于認證授權(quán)的核心API,以及認證授權(quán)的執(zhí)行流程和底層原理。掌握了這些之后,對于Spring Security,我們不僅做到了 "知其然",而且也做到了 "知其所以然"

在現(xiàn)在的求職環(huán)境下,只知道某個技能點的用法是遠遠不夠的,面試官會要求我們研究某個技術(shù)的底層實現(xiàn)原理,所以雖然前面的兩章內(nèi)容掌握起來很有難度,但是還是希望各位小伙伴結(jié)合源碼認真研讀,這樣你才能在編程之路上走的更遠更高!

總是研究底層,對于我們初學(xué)者來說,既有難度,也會影響咱們的學(xué)習(xí)積極性,所以從本篇文章開始,咱們繼續(xù)學(xué)習(xí)Spring Security的其他用法,比如我們學(xué)習(xí)一下如何在Spring Security中添加執(zhí)行自定義的過濾器,進而實現(xiàn)驗證碼校驗功能。

一. 驗證碼簡介

在進行驗證碼編碼實現(xiàn)之前,壹哥 先給各位介紹一下驗證碼的概念和作用。

驗證碼(CAPTCHA):全稱是Completely Automated Public Turing test to tell Computers and Humans Apart,翻譯過來就是“全自動區(qū)分計算機和人類的圖靈測試”。通俗的講,驗證碼就是為了防止惡意用戶采用暴力重試的攻擊手段而設(shè)置的一種防護措施。我們在進行用戶注冊、登錄、或者論壇發(fā)帖時都可以利用驗證碼,對某些惡意用戶利用計算機發(fā)起無限重試進行必要的攔截限制。

接下來在Spring Security的環(huán)境中,我們可以用如下兩種方案實現(xiàn)圖形驗證碼:

  • 基于自定義的過濾器來實現(xiàn)圖形驗證碼;
  • 基于自定義的認證器來實現(xiàn)圖形驗證碼。

在本篇文章中,壹哥 先利用第一種方案,也就是基于自定義的過濾器的方式,來教會大家如何實現(xiàn)圖形驗證碼,請繼續(xù)往下看哦。

二. 基于過濾器實現(xiàn)圖形驗證碼

1. 實現(xiàn)概述

在Spring Security中,實現(xiàn)驗證碼校驗的方式有很多種,其中基于過濾器來實現(xiàn)圖形驗證碼是最簡單的方式。小伙伴可能會問,過濾器如何實現(xiàn)驗證碼校驗功能呢?基于什么原理?這個其實很簡單,流程原理就是我們先自定義一個過濾器Filter,處理驗證碼的驗證邏輯,然后把該過濾器添加到Spring Security過濾器鏈的某個合適位置。當(dāng)匹配到登錄請求時,過濾器會對驗證碼進行校驗,如果成功則放行,如果失敗則結(jié)束當(dāng)前驗證請求。

明白了實現(xiàn)流程和原理后,接下來我們就在之前項目的基礎(chǔ)之上,進行驗證碼功能的代碼實現(xiàn)。

2. 創(chuàng)建新模塊

我們可以創(chuàng)建一個新的項目model,創(chuàng)建過程與之前一樣,這里就略過了。

3. 添加依賴包

本案例中,我們采用github上的開源驗證碼解決方案kaptcha,所以需要在原有項目的基礎(chǔ)上添加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>

4. 創(chuàng)建Producer對象

在準(zhǔn)備好依賴包之后,接下來我們創(chuàng)建一個CaptchaConfig配置類,在該類中創(chuàng)建一個Producer對象,對驗證碼對象進行必要的配置,比如設(shè)置驗證碼背景框的寬度和高度,驗證碼的字符集,驗證碼的個數(shù)等。

@Configuration
public class CaptchaConfig {
 
    @Bean
    public Producer captcha() {
        // 配置圖形驗證碼的基本參數(shù)
        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);
        // 使用默認的圖形驗證碼實現(xiàn),當(dāng)然也可以自定義實現(xiàn)
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
 
}

5. 創(chuàng)建生成驗證碼的接口

在上面創(chuàng)建了Producer對象后,接著我們再創(chuàng)建一個生成驗證碼的接口,該接口中負責(zé)生成驗證碼圖片,并且記得要把生成的驗證碼存放到session中,以便后面發(fā)起登錄請求時進行比對驗證碼。

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

6. 自定義異常

我們可以自定義一個運行時異常,用于處理驗證碼校驗失敗時拋出異常提示信息,當(dāng)然這個并不是必須的。

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

7. 創(chuàng)建攔截驗證碼的過濾器

創(chuàng)建驗證碼并保存到session之后,另一個很重要的工作就是比對用戶從前端傳遞過來的驗證碼是否相同,這個比對工作我們就在自定義的過濾器中進行實現(xiàn)。所以接著我們就創(chuàng)建一個過濾器,負責(zé)對用戶發(fā)來的驗證碼進行攔截校驗,看看request請求中傳遞過來的驗證碼,與我們生成并保存在session中的驗證碼是否一致。

/**
 * 基于過濾器實現(xiàn)圖形驗證碼的驗證功能,這屬于Servlet層面,簡單易理解.
 */
public class VerificationCodeFilter extends OncePerRequestFilter {
 
    private AuthenticationFailureHandler authenticationFailureHandler = new SecurityAuthenticationFailureHandler();
 
    @Overre
    protected vo doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        // 非登錄請求不校驗驗證碼,直接放行
        if (!"/login".equals(httpServletRequest.getRequestURI())) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } else {
            try {
                //校驗驗證碼
                verificationCode(httpServletRequest);
                
                //驗證碼校驗通過后,對請求進行放行
                filterChain.doFilter(httpServletRequest, httpServletResponse);
            } catch (VerificationCodeException e) {
                authenticationFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);
            }
        }
    }
 
    public vo verificationCode (HttpServletRequest httpServletRequest) throws VerificationCodeException {
        HttpSession session = httpServletRequest.getSession();
        String savedCode = (String) session.getAttribute("captcha");
        if (!StringUtils.isEmpty(savedCode)) {
            // 隨手清除驗證碼,不管是失敗還是成功,所以客戶端應(yīng)在登錄失敗時刷新驗證碼
            session.removeAttribute("captcha");
        }
 
        String requestCode = httpServletRequest.getParameter("captcha");
        // 校驗不通過拋出異常
        if (StringUtils.isEmpty(requestCode) || StringUtils.isEmpty(savedCode) || !requestCode.equals(savedCode)) {
            throw new VerificationCodeException();
        }
    }
 
}

8. 編寫SecurityConfig

接下來我們需要編寫一個SecurityConfig配置類,在該配置類中,把咱們前面編寫的驗證碼過濾器添加在默認的UsernamePasswordAuthenticationFilter過濾器之前來執(zhí)行,可以利用http.addFilterBefore()方法來實現(xiàn)。

對于UsernamePasswordAuthenticationFilter過濾器,你還能想起來嗎?如果想不起來,請看我前一篇文章,里面有詳細講解哦!

/**
 * @Author: 一一哥
 * 增加圖形驗證碼功能.
 */
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @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()
                .failureHandler(new SecurityAuthenticationFailureHandler())
                .successHandler(new SecurityAuthenticationSuccessHandler())
                .loginPage("/myLogin.html")
                .loginProcessingUrl("/login")
                .permitAll()
                .and()
                .csrf()
                .disable();
 
        //將過濾器添加在UsernamePasswordAuthenticationFilter之前
        http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
 
}

在這里,我們把自定義的驗證碼校驗過濾器VerificationCodeFilter,添加到了Spring Security自帶的UsernamePasswordAuthenticationFilter過濾器前面。

注:

關(guān)于我們測試的web接口,數(shù)據(jù)庫配置、認證成功、失敗時的Handler處理器等,請參考前面《基于Spring Security前后端分離的權(quán)限控制系統(tǒng)問題》案例,此處略過。

9. 編寫測試頁面

既然要實現(xiàn)驗證碼功能,為了方便測試,我們需要編寫一個自定義的登錄頁面,并在這里添加對驗證碼接口的引用,這里列出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" alt="captcha" height="50px" wth="150px" style="margin-left: 20px;">
                 </div>
                 <div class="forgot">
                     <a href="#">忘記密碼</a>
                     <input type="submit" value="登錄" >
                 </div>
            </form>
       </div>
       <div class="login-bottom">
           <h3>新用戶&nbsp;<a href="#">注&nbsp;冊</a></h3>
       </div>
   </div>
</body>

10. 代碼結(jié)構(gòu)

整個項目的代碼結(jié)構(gòu)如下,請參考下圖進行實現(xiàn)。

11. 啟動項目測試

接下來我們啟動項目,在訪問受限接口時,會重定向到myLogin.html登錄頁面,可以看到我們的驗證碼效果已經(jīng)顯示出來了。

接下來我們輸入正確的用戶名、密碼、驗證碼后,就可以成功的登錄進去訪問web接口了。

至此,基于自定義過濾器實現(xiàn)的驗證碼功能,壹哥 就帶各位實現(xiàn)完畢,你學(xué)會了嗎?如有疑問,可以在評論區(qū)留言。

到此這篇關(guān)于Spring Security基于過濾器實現(xiàn)圖形驗證碼功能的文章就介紹到這了,更多相關(guān)Spring Security圖形驗證碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 超詳細講解Java秒殺項目登陸模塊的實現(xiàn)

    超詳細講解Java秒殺項目登陸模塊的實現(xiàn)

    這是一個主要使用java開發(fā)的秒殺系統(tǒng),項目比較大,所以本篇只實現(xiàn)了登陸模塊,代碼非常詳盡,感興趣的朋友快來看看
    2022-03-03
  • java中main函數(shù)你知道多少

    java中main函數(shù)你知道多少

    大家好,本篇文章主要講的是java中main函數(shù)你知道多少,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • 解決本機安裝的JDK8,啟動IDEA2019沒反應(yīng)的問題(開發(fā)工具)

    解決本機安裝的JDK8,啟動IDEA2019沒反應(yīng)的問題(開發(fā)工具)

    這篇文章主要介紹了解決本機安裝的JDK8啟動IDEA2019沒反應(yīng)的問題(開發(fā)工具),非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • 零基礎(chǔ)寫Java知乎爬蟲之將抓取的內(nèi)容存儲到本地

    零基礎(chǔ)寫Java知乎爬蟲之將抓取的內(nèi)容存儲到本地

    上一回我們說到了如何把知乎的某些內(nèi)容爬取出來,那么這一回我們就說說怎么把這些內(nèi)容存儲到本地吧。
    2014-11-11
  • Java 輕松實現(xiàn)二維數(shù)組與稀疏數(shù)組互轉(zhuǎn)

    Java 輕松實現(xiàn)二維數(shù)組與稀疏數(shù)組互轉(zhuǎn)

    在某些應(yīng)用場景中需要大量的二維數(shù)組來進行數(shù)據(jù)存儲,但是二維數(shù)組中卻有著大量的無用的位置占據(jù)著內(nèi)存空間,稀疏數(shù)組就是為了優(yōu)化二維數(shù)組,節(jié)省內(nèi)存空間
    2022-04-04
  • 簡單談?wù)凧ava中的棧和堆

    簡單談?wù)凧ava中的棧和堆

    堆和棧都是Java用來在RAM中存放數(shù)據(jù)的地方,下面這篇文章主要給大家介紹了關(guān)于Java中棧和堆的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-11-11
  • java 值Document解析xml詳細介紹

    java 值Document解析xml詳細介紹

    這篇文章主要介紹了java 值Document解析xml詳細介紹的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 如何在maven本地倉庫中添加oracle的jdbc驅(qū)動

    如何在maven本地倉庫中添加oracle的jdbc驅(qū)動

    文章介紹了在Maven項目中添加Oracle數(shù)據(jù)庫驅(qū)動ojdbc5時遇到的問題以及解決問題的兩種方法,方法一為簡單粗暴,但沒有體現(xiàn)Maven倉庫的作用,需要手動管理jar包,方法二為在Maven本地倉庫中添加Oracle的JDBC驅(qū)動,過程較為繁瑣,但配置一次后可以多次使用
    2024-11-11
  • JAVA實現(xiàn)JSON后端向前端傳遞數(shù)據(jù)

    JAVA實現(xiàn)JSON后端向前端傳遞數(shù)據(jù)

    本篇文章主要介紹了JAVA實現(xiàn)JSON后端向前端傳遞數(shù)據(jù),這里整理了詳細的代碼,具有一定的參考價值,有需要的小伙伴可以參考下。
    2017-03-03
  • Spring核心思想之淺談IoC容器與依賴倒置(DI)

    Spring核心思想之淺談IoC容器與依賴倒置(DI)

    文章介紹了Spring的IoC和DI機制,以及MyBatis的動態(tài)代理,通過注解和反射,Spring能夠自動管理對象的創(chuàng)建和依賴注入,而MyBatis則通過動態(tài)代理實現(xiàn)了接口方法到數(shù)據(jù)庫操作的映射,文章詳細解釋了Spring和MyBatis的工作原理,并通過示例代碼展示了它們的結(jié)合使用方式
    2025-01-01

最新評論

朝阳县| 博白县| 海阳市| 朝阳市| 米易县| 图木舒克市| 辽宁省| 巧家县| 周宁县| 唐山市| 郯城县| 胶州市| 离岛区| 渭源县| 马边| 隆子县| 石屏县| 遂平县| 曲麻莱县| 云霄县| 郓城县| 玉溪市| 隆子县| 泰宁县| 保定市| 星座| 寿宁县| 淮南市| 乌兰县| 西丰县| 荔浦县| 夹江县| 长岭县| 同江市| 洛隆县| 广宗县| 鸡东县| 河曲县| 尚志市| 姜堰市| 忻州市|