欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

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

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

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

一. 驗(yàn)證碼簡介

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

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

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

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

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

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

1. 實(shí)現(xiàn)概述

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

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

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

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

3. 添加依賴包

本案例中,我們采用github上的開源驗(yàn)證碼解決方案kaptcha,所以需要在原有項(xiàng)目的基礎(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對(duì)象

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

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

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

在上面創(chuàng)建了Producer對(duì)象后,接著我們?cè)賱?chuàng)建一個(gè)生成驗(yàn)證碼的接口,該接口中負(fù)責(zé)生成驗(yàn)證碼圖片,并且記得要把生成的驗(yàn)證碼存放到session中,以便后面發(fā)起登錄請(qǐng)求時(shí)進(jìn)行比對(duì)驗(yàn)證碼。

@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)建驗(yàn)證碼文本
        String capText = captchaProducer.createText();
        
        // 將驗(yàn)證碼文本設(shè)置到session
        request.getSession().setAttribute("captcha", capText);
        
        // 創(chuàng)建驗(yàn)證碼圖片
        BufferedImage bi = captchaProducer.createImage(capText);
        // 獲取響應(yīng)輸出流
        ServletOutputStream out = response.getOutputStream();
        // 將圖片驗(yàn)證碼數(shù)據(jù)寫到響應(yīng)輸出流
        ImageIO.write(bi, "jpg", out);
        
        // 推送并關(guān)閉響應(yīng)輸出流
        try {
            out.flush();
        } finally {
            out.close();
        }
    }
 
}

6. 自定義異常

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

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

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

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

/**
 * 基于過濾器實(shí)現(xiàn)圖形驗(yàn)證碼的驗(yà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 {
        // 非登錄請(qǐng)求不校驗(yàn)驗(yàn)證碼,直接放行
        if (!"/login".equals(httpServletRequest.getRequestURI())) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
        } else {
            try {
                //校驗(yàn)驗(yàn)證碼
                verificationCode(httpServletRequest);
                
                //驗(yàn)證碼校驗(yàn)通過后,對(duì)請(qǐng)求進(jìn)行放行
                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àn)證碼,不管是失敗還是成功,所以客戶端應(yīng)在登錄失敗時(shí)刷新驗(yàn)證碼
            session.removeAttribute("captcha");
        }
 
        String requestCode = httpServletRequest.getParameter("captcha");
        // 校驗(yàn)不通過拋出異常
        if (StringUtils.isEmpty(requestCode) || StringUtils.isEmpty(savedCode) || !requestCode.equals(savedCode)) {
            throw new VerificationCodeException();
        }
    }
 
}

8. 編寫SecurityConfig

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

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

/**
 * @Author: 一一哥
 * 增加圖形驗(yàn)證碼功能.
 */
@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();
    }
 
}

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

注:

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

9. 編寫測(cè)試頁面

既然要實(shí)現(xiàn)驗(yàn)證碼功能,為了方便測(cè)試,我們需要編寫一個(gè)自定義的登錄頁面,并在這里添加對(duì)驗(yàn)證碼接口的引用,這里列出html頁面的核心代碼。

<body>
    <div class="login">
        <h2>Access Form</h2>
        <div class="login-top">
            <h1>登錄驗(yàn)證</h1>
            <form action="/login" method="post">
                 <input type="text" name="username" placeholder="username" />
                 <input type="password" name="password" placeholder="password" />
                 <div style="display: flex;">
                     <!-- 新增圖形驗(yàn)證碼的輸入框 -->
                     <input type="text" name="captcha" placeholder="captcha" />
                     <!-- 圖片指向圖形驗(yàn)證碼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;冊(cè)</a></h3>
       </div>
   </div>
</body>

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

整個(gè)項(xiàng)目的代碼結(jié)構(gòu)如下,請(qǐng)參考下圖進(jìn)行實(shí)現(xiàn)。

11. 啟動(dòng)項(xiàng)目測(cè)試

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

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

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

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

相關(guān)文章

  • 在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫

    在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫

    這篇文章主要介紹了在Java的Spring框架的程序中使用JDBC API操作數(shù)據(jù)庫的方法,并通過示例展示了其存儲(chǔ)過程以及基本SQL語句的應(yīng)用,需要的朋友可以參考下
    2015-12-12
  • Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問題解決

    Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問題解決

    項(xiàng)目基于 SpringBoot + MybatisPlus 3.5.2 使用數(shù)據(jù)庫自增ID時(shí), 出現(xiàn)重復(fù)鍵的問題,本文就來介紹一下解決方法,感興趣的可以了解一下
    2023-09-09
  • MybatisPlus #{param}和${param}的用法詳解

    MybatisPlus #{param}和${param}的用法詳解

    這篇文章主要介紹了MybatisPlus #{param}和${param}的用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 詳解Java分布式IP限流和防止惡意IP攻擊方案

    詳解Java分布式IP限流和防止惡意IP攻擊方案

    這篇文章主要介紹了詳解Java分布式IP限流和防止惡意IP攻擊方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 詳解SpringCloud-Alibaba-Seata分布式事務(wù)

    詳解SpringCloud-Alibaba-Seata分布式事務(wù)

    這篇文章主要介紹了SpringCloud-Alibaba-Seata分布式事務(wù)的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Java編程時(shí)間日期API實(shí)例解析

    Java編程時(shí)間日期API實(shí)例解析

    本文主要介紹了Java編程時(shí)間日期API實(shí)例解析的相關(guān)內(nèi)容,分享了一則實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2018-01-01
  • Java深度優(yōu)先遍歷解決排列組合問題詳解

    Java深度優(yōu)先遍歷解決排列組合問題詳解

    這篇文章主要介紹了Java深度優(yōu)先遍歷解決排列組合問題詳解,深度優(yōu)先搜索是遞歸過程,帶有回退操作,因此需要使用棧存儲(chǔ)訪問的路徑信息,當(dāng)訪問到的當(dāng)前頂點(diǎn)沒有可以前進(jìn)的鄰接頂點(diǎn)時(shí),需要進(jìn)行出棧操作,將當(dāng)前位置回退至出棧元素位置,需要的朋友可以參考下
    2024-01-01
  • 在logback.xml中自定義動(dòng)態(tài)屬性的方法

    在logback.xml中自定義動(dòng)態(tài)屬性的方法

    這篇文章主要介紹了在logback.xml中自定義動(dòng)態(tài)屬性的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java實(shí)現(xiàn)更新順序表中的指定元素的示例

    Java實(shí)現(xiàn)更新順序表中的指定元素的示例

    本文主要介紹了Java實(shí)現(xiàn)更新順序表中的指定元素的示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Java轉(zhuǎn)JSON串的幾種方式

    Java轉(zhuǎn)JSON串的幾種方式

    本文給大家總結(jié)一下java轉(zhuǎn)json串的幾種方式,每種方式通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨腳本之家小編一起學(xué)習(xí)吧
    2018-05-05

最新評(píng)論