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

Spring Security基于自定義的認(rèn)證提供器實(shí)現(xiàn)圖形驗(yàn)證碼流程解析

 更新時間:2021年09月26日 11:16:01   作者:一一哥Sun  
這篇文章主要介紹了Spring Security基于自定義的認(rèn)證提供器實(shí)現(xiàn)圖形驗(yàn)證碼,通過本文學(xué)習(xí)下AuthenticationProvider接口的類關(guān)系圖,感興趣的朋友跟隨小編一起看看吧

前言

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

一. 認(rèn)證提供器簡介

在上一章節(jié)中,我?guī)Ц魑焕米远x的過濾器實(shí)現(xiàn)了圖形驗(yàn)證碼效果,接下來我們利用另一種方式,基于自定義的認(rèn)證提供器來實(shí)現(xiàn)圖形驗(yàn)證碼。

1. 認(rèn)證提供器AuthenticationProver

在第11章節(jié)中,壹哥 給大家講過Spring Security的認(rèn)證授權(quán)實(shí)現(xiàn)流程,其中就給大家講解過AuthenticationProver的作用,接下來我們看一下AuthenticationProver接口的類關(guān)系圖:

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

我們可以通過編寫一個子類繼承AbstractUserDetailsAuthenticationProver,復(fù)寫這2個抽象方法,進(jìn)行滿足自己需求的擴(kuò)展實(shí)現(xiàn)。Spring Security中的DaoAuthenticationProver子類就是通過復(fù)寫這2個抽象方法,實(shí)現(xiàn)了基于數(shù)據(jù)庫模型的認(rèn)證授權(quán)。

我們今天會通過繼承DaoAuthenticationProver,來實(shí)現(xiàn)圖形驗(yàn)證碼的校驗(yàn)功能。

2. WebAuthenticationDetails類介紹

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

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

了解完上面的這些必要的API,我們就可以實(shí)現(xiàn)今天的需求了。

二. 實(shí)現(xiàn)圖形驗(yàn)證碼

1. 添加依賴包

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

在本案例中我們依然采用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>

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

跟上一個案例一樣,創(chuàng)建CaptchaConfig配置類,在該類中創(chuàng)建一個Producer對象,對驗(yàn)證碼對象進(jìn)行必要的配置。

@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;
    }
 
}

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

在上面創(chuàng)建了Producer對象后,接著創(chuàng)建一個生成驗(yàn)證碼的接口,該接口中負(fù)責(zé)生成驗(yàn)證碼圖片,并將驗(yàn)證碼存儲到session中。

@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();
        }
    }
 
}

4. 自定義異常

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

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

5. 自定義WebAuthenticationDetails

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

/**
 * 添加額外的用戶認(rèn)證信息
 */  
public class MyWebAuthenticationDetails extends WebAuthenticationDetails {
 
    private String imageCode;
 
    private String savedImageCode;
 
    public String getImageCode() {
        return imageCode;
    }
 
    public String getSavedImageCode() {
        return savedImageCode;
    }
 
    /**
     * 補(bǔ)充用戶提交的驗(yàn)證碼和session保存的驗(yàn)證碼
     */  
    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)) {
            // 隨手清除驗(yàn)證碼,不管是失敗還是成功,所以客戶端應(yīng)在登錄失敗時刷新驗(yàn)證碼
            session.removeAttribute("captcha");
        }
    }
 
}

6. 自定義AuthenticationDetailsSource

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

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

@Component
public class MyWebAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails> {
 
    /**
     * 創(chuàng)建一個WebAuthenticationDetails對象
     */  
    @Overre
    public WebAuthenticationDetails buildDetails(HttpServletRequest request) {
 
        return new MyWebAuthenticationDetails(request);
    }
 
}

7. 自定義DaoAuthenticationProver

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

/**
 * 在常規(guī)的數(shù)據(jù)庫認(rèn)證之上,添加圖形驗(yàn)證碼功能
 */
@Component
public class MyAuthenticationProver extends DaoAuthenticationProver {
 
    /**
     * 構(gòu)造方法注入U(xiǎn)serDetailService和PasswordEncoder
     */
    public MyAuthenticationProver(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        this.setUserDetailsService(userDetailsService);
        this.setPasswordEncoder(passwordEncoder);
    }
 
    /**
     * 在常規(guī)的認(rèn)證之上,添加額外的圖形驗(yàn)證碼功能
     */
    @Overre
    protected vo additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
        //獲取token令牌中關(guān)聯(lián)的details對象,并將其轉(zhuǎn)換為我們自定義的MyWebAuthenticationDetails
        MyWebAuthenticationDetails details = (MyWebAuthenticationDetails) usernamePasswordAuthenticationToken.getDetails();
        String imageCode = details.getImageCode();
        String savedImageCode = details.getSavedImageCode();
        
        // 檢驗(yàn)圖形驗(yàn)證碼
        if (StringUtils.isEmpty(imageCode) || StringUtils.isEmpty(savedImageCode) || !imageCode.equals(savedImageCode)) {
            throw new VerificationCodeException();
        }
 
        //在正常的認(rèn)證檢查之前,添加額外的關(guān)于圖形驗(yàn)證碼的校驗(yàn)
        super.additionalAuthenticationChecks(userDetails, usernamePasswordAuthenticationToken);
    }
 
}

8. 添加SecurityConfig

然后創(chuàng)建編寫SecurityConfig類,關(guān)聯(lián)配置我們前面編寫的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()
            	//這里關(guān)聯(lián)配置自定義的AuthenticationDetailsSource
                .authenticationDetailsSource(myWebAuthenticationDetailsSource)
                .failureHandler(new SecurityAuthenticationFailureHandler())
                .successHandler(new SecurityAuthenticationSuccessHandler())
                .loginPage("/myLogin.html")
                .loginProcessingUrl("/login")
                .permitAll()
                .and()
                .csrf()
                .disable();
    }
 
    //在這里關(guān)聯(lián)我們自定義的AuthenticationProver
    @Overre
    protected vo configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProver(authenticationProver);
    }
 
    @Bean
    public PasswordEncoder passwordEncoder() {
 
        return NoOpPasswordEncoder.getInstance();
    }
 
}

9. 編寫測試頁面

最后編寫一個自定義的登錄頁面,在這里添加對驗(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="#" 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. 代碼結(jié)構(gòu)

本案例的主要代碼結(jié)構(gòu)如下圖所示,各位可以參考創(chuàng)建。

11. 啟動項(xiàng)目測試

接下來我們啟動項(xiàng)目,跳轉(zhuǎn)到登錄頁面后,我們就可以看到驗(yàn)證碼已經(jīng)被創(chuàng)建出來了。

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

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

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

相關(guān)文章

  • linux系統(tǒng)下java項(xiàng)目在后臺啟動的4種方式總結(jié)

    linux系統(tǒng)下java項(xiàng)目在后臺啟動的4種方式總結(jié)

    Linux是集多種功能于一身的操作系統(tǒng),它可以讓用戶查看和管理當(dāng)下正在運(yùn)行的進(jìn)程,包括Java程序,這篇文章主要給大家總結(jié)介紹了關(guān)于linux系統(tǒng)下java項(xiàng)目在后臺啟動的4種方式,需要的朋友可以參考下
    2023-10-10
  • SpringBoot通過注解下載任意對象

    SpringBoot通過注解下載任意對象

    下載功能應(yīng)該是比較常見的功能了,雖然一個項(xiàng)目里面可能出現(xiàn)的不多,但是基本上每個項(xiàng)目都會有,而且有些下載功能其實(shí)還是比較繁雜的,這篇文章主要介紹了SpringBoot一個注解就能幫你下載任意對象,需要的朋友可以參考下
    2023-08-08
  • 使用Java計(jì)算屏幕的PPI的方法詳解

    使用Java計(jì)算屏幕的PPI的方法詳解

    在現(xiàn)代電子設(shè)備中,屏幕的分辨率和顯示效果是用戶非常關(guān)注的一個指標(biāo),PPI(Pixels Per Inch,每英寸像素?cái)?shù))是衡量屏幕顯示精度的重要參數(shù)之一,PPI越高,屏幕顯示的圖像越細(xì)膩,視覺效果越好,本文將詳細(xì)介紹PPI的概念、計(jì)算方法,并通過Java代碼實(shí)現(xiàn)PPI的計(jì)算
    2025-02-02
  • Java老手該當(dāng)心的13個錯誤

    Java老手該當(dāng)心的13個錯誤

    這篇文章主要介紹了Java老手該當(dāng)心的13個錯誤,需要的朋友可以參考下
    2015-04-04
  • Java?Git?Commit?Message使用規(guī)范

    Java?Git?Commit?Message使用規(guī)范

    這篇文章主要介紹了Java?Git?Commit?Message使用規(guī)范,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下,希望對你的學(xué)習(xí)有所幫助
    2022-08-08
  • mybatis中string和date的轉(zhuǎn)換方式

    mybatis中string和date的轉(zhuǎn)換方式

    這篇文章主要介紹了mybatis中string和date的轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot實(shí)現(xiàn)配置文件自動加載和刷新的示例詳解

    SpringBoot實(shí)現(xiàn)配置文件自動加載和刷新的示例詳解

    在使用Spring Boot開發(fā)應(yīng)用程序時,配置文件是非常重要的組成部分,在不同的環(huán)境中,我們可能需要使用不同的配置文件,當(dāng)我們更改配置文件時,我們希望應(yīng)用程序能夠自動加載和刷新配置文件,本文我們將探討Spring Boot如何實(shí)現(xiàn)配置文件的自動加載和刷新
    2023-08-08
  • 使用Mybatis遇到的坑之Integer類型參數(shù)的解讀

    使用Mybatis遇到的坑之Integer類型參數(shù)的解讀

    這篇文章主要介紹了使用Mybatis遇到的坑之Integer類型參數(shù)的解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • java解壓zip文件示例

    java解壓zip文件示例

    這篇文章主要介紹了java解壓zip文件示例,在獲得一個以Zip格式壓縮的文件之后,需要將其進(jìn)行解壓縮,還原成壓縮前的文件,下面是代碼示例
    2014-03-03
  • Java實(shí)現(xiàn)帶GUI的氣泡詩詞效果

    Java實(shí)現(xiàn)帶GUI的氣泡詩詞效果

    這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)帶GUI的氣泡詩詞效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定幫助,感興趣的可以了解一下
    2022-12-12

最新評論

雷州市| 当雄县| 拉孜县| 西乡县| 容城县| 都昌县| 大名县| 余江县| 宝兴县| 勐海县| 闽侯县| 宜兰市| 怀来县| 沙田区| 泗阳县| 兴城市| 齐河县| 罗田县| 蚌埠市| 桦南县| 镇江市| 五大连池市| 安西县| 墨竹工卡县| 安多县| 永修县| 阿坝| 仲巴县| 阳信县| 襄汾县| 高州市| 左云县| 乐山市| 安国市| 烟台市| 天气| 鄂州市| 司法| 平乐县| 台南县| 凌海市|