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

Springboot+SpringSecurity實(shí)現(xiàn)圖片驗(yàn)證碼登錄的示例

 更新時(shí)間:2022年04月15日 09:37:41   作者:山河已無(wú)恙  
本文主要介紹了Springboot+SpringSecurity實(shí)現(xiàn)圖片驗(yàn)證碼登錄的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

這個(gè)問(wèn)題,網(wǎng)上找了好多,結(jié)果代碼都不全,找了好多,要不是就自動(dòng)注入的類注入不了,編譯報(bào)錯(cuò),要不異常捕獲不了浪費(fèi)好多時(shí)間,就覺(jué)得,框架不熟就不能隨便用,全是坑,氣死我了,最后改了兩天.終于弄好啦;

問(wèn)題主要是:

  • 返回的驗(yàn)證碼不知道在SpringSecurity的什么地方和存在內(nèi)存里的比較?我用的方法是前置一個(gè)過(guò)濾器,插入到表單驗(yàn)證之前。
  • 比較之后應(yīng)該怎么處理,:比較之后要拋出一個(gè)繼承了AuthenticationException的異常
  • 其次是捕獲驗(yàn)證碼錯(cuò)誤異常的處理? 捕獲到的異常交給自定義驗(yàn)證失敗處理器AuthenticationFailureHandler處理,這里,用的處理器要和表單驗(yàn)證失敗的處理器是同一個(gè)處理器,不然會(huì)報(bào)異常,所以在需要寫一個(gè)全局的AuthenticationFailureHandler的實(shí)現(xiàn)類,專門用來(lái)處理異常。表單驗(yàn)證有成功和失敗兩個(gè)處理器,我們一般直接以匿名內(nèi)部類形似寫。要是加了驗(yàn)證碼,就必須使用統(tǒng)一的失敗處理器。

效果圖

網(wǎng)上大都是直接注入一個(gè)AuthenticationFailureHandler,我當(dāng)時(shí)就不明白這個(gè)咋注進(jìn)去的,我這個(gè)一寫就報(bào)錯(cuò),注入不進(jìn)去,后來(lái)就想自己new一個(gè)哇,可以是可以了,但是還報(bào)異常,java.lang.IllegalStateException: Cannot call sendError() after the response has been committed,后來(lái)想表單驗(yàn)證的時(shí)候,失敗用的也是這個(gè)處理器,就想定義一個(gè)全局的處理器,

package com.liruilong.hros.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liruilong.hros.Exception.ValidateCodeException;
import com.liruilong.hros.model.RespBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2020/2/11 23:08
 */
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter out = httpServletResponse.getWriter();
        RespBean respBean = RespBean.error(e.getMessage());
           // 驗(yàn)證碼自定義異常的處理
        if (e instanceof ValidateCodeException){
            respBean.setMsg(e.getMessage());
            //Security內(nèi)置的異常處理
        }else if (e instanceof LockedException) {
            respBean.setMsg("賬戶被鎖定請(qǐng)聯(lián)系管理員!");
        } else if (e instanceof CredentialsExpiredException) {
            respBean.setMsg("密碼過(guò)期請(qǐng)聯(lián)系管理員!");
        } else if (e instanceof AccountExpiredException) {
            respBean.setMsg("賬戶過(guò)期請(qǐng)聯(lián)系管理員!");
        } else if (e instanceof DisabledException) {
            respBean.setMsg("賬戶被禁用請(qǐng)聯(lián)系管理員!");
        } else if (e instanceof BadCredentialsException) {
            respBean.setMsg("用戶名密碼輸入錯(cuò)誤,請(qǐng)重新輸入!");
        }
        //將hr轉(zhuǎn)化為Sting
        out.write(new ObjectMapper().writeValueAsString(respBean));
        out.flush();
        out.close();
    }
    @Bean
    public  MyAuthenticationFailureHandler getMyAuthenticationFailureHandler(){
        return new MyAuthenticationFailureHandler();
    }
}

流程 

  1.  請(qǐng)求登錄頁(yè),將驗(yàn)證碼結(jié)果存到基于Servlet的session里,以JSON格式返回驗(yàn)證碼,
  2. 之后前端發(fā)送登錄請(qǐng)求,SpringSecurity中處理,自定義一個(gè)filter讓它繼承自O(shè)ncePerRequestFilter,然后重寫doFilterInternal方法,在這個(gè)方法中實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證的功能,如果驗(yàn)證碼錯(cuò)誤就拋出一個(gè)繼承自AuthenticationException的驗(yàn)證嗎錯(cuò)誤的異常消息寫入到響應(yīng)消息中.
  3. 之后返回異常信息交給自定義驗(yàn)證失敗處理器處理。

下面以這個(gè)順序書(shū)寫代碼:

依賴大家照著import導(dǎo)一下吧,記得有這兩個(gè),驗(yàn)證碼需要一個(gè)依賴,之后還使用了一個(gè)工具依賴包,之后是前端代碼

?<!--圖片驗(yàn)證-->
        <dependency>
            <groupId>com.github.whvcse</groupId>
            <artifactId>easy-captcha</artifactId>
            <version>1.6.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <div class="login-code">
          <img :src="codeUrl"
               @click="getCode">
        </div>
 
     

后端代碼:

獲取驗(yàn)證碼,將結(jié)果放到session里

package com.liruilong.hros.controller;
 
import com.liruilong.hros.model.RespBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.wf.captcha.ArithmeticCaptcha;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
 
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/12/19 19:58
 */
@RestController
public class LoginController {
    
    @GetMapping(value = "/auth/code")
    public Map getCode(HttpServletRequest request,HttpServletResponse response){
        // 算術(shù)類型 https://gitee.com/whvse/EasyCaptcha
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
        // 幾位數(shù)運(yùn)算,默認(rèn)是兩位
        captcha.setLen(2);
        // 獲取運(yùn)算的結(jié)果
        String result = captcha.text();
        System.err.println("生成的驗(yàn)證碼:"+result);
        // 保存
        // 驗(yàn)證碼信息
        Map<String,Object> imgResult = new HashMap<String,Object>(2){{
            put("img", captcha.toBase64());
    
        }};
        request.getSession().setAttribute("yanzhengma",result);
 
        return imgResult;
    }
}

定義一個(gè)VerifyCodeFilter 過(guò)濾器

package com.liruilong.hros.filter;
 
 
import com.liruilong.hros.Exception.ValidateCodeException;
import com.liruilong.hros.config.MyAuthenticationFailureHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
 
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2020/2/7 19:39
 */
@Component
public class VerifyCodeFilter extends OncePerRequestFilter {
 
    @Bean
    public VerifyCodeFilter getVerifyCodeFilter() {
        return new VerifyCodeFilter();
    }
    @Autowired
    MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
 
        if (StringUtils.equals("/doLogin", request.getRequestURI())
                && StringUtils.equalsIgnoreCase(request.getMethod(), "post")) {
            // 1. 進(jìn)行驗(yàn)證碼的校驗(yàn)
            try {
            String requestCaptcha = request.getParameter("code");
                if (requestCaptcha == null) {
                    throw new ValidateCodeException("驗(yàn)證碼不存在");
                }
            String code = (String) request.getSession().getAttribute("yanzhengma");
                if (StringUtils.isBlank(code)) {
                    throw new ValidateCodeException("驗(yàn)證碼過(guò)期!");
                }
            code = code.equals("0.0") ? "0" : code;
            logger.info("開(kāi)始校驗(yàn)驗(yàn)證碼,生成的驗(yàn)證碼為:" + code + " ,輸入的驗(yàn)證碼為:" + requestCaptcha);
                if (!StringUtils.equals(code, requestCaptcha)) {
                    throw new ValidateCodeException("驗(yàn)證碼不匹配");
                }
            } catch (AuthenticationException e) {
                // 2. 捕獲步驟1中校驗(yàn)出現(xiàn)異常,交給失敗處理類進(jìn)行進(jìn)行處理
                myAuthenticationFailureHandler.onAuthenticationFailure(request, response, e);
            } finally {
                filterChain.doFilter(request, response);
            }
        } else {
            filterChain.doFilter(request, response);
        }
 
 
    }
 
}

定義一個(gè)自定義異常處理,繼承AuthenticationException  

package com.liruilong.hros.Exception;
 
 
import org.springframework.security.core.AuthenticationException;
 
 
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2020/2/8 7:24
 */
 
public class ValidateCodeException extends AuthenticationException  {
 
    public ValidateCodeException(String msg) {
        super(msg);
    }
 
 
}

security配置. 

在之前的基礎(chǔ)上加filter的基礎(chǔ)上加了

http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class),驗(yàn)證處理上,驗(yàn)證碼和表單驗(yàn)證失敗用同一個(gè)失敗處理器,

package com.liruilong.hros.config;
 
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liruilong.hros.filter.VerifyCodeFilter;
import com.liruilong.hros.model.Hr;
import com.liruilong.hros.model.RespBean;
import com.liruilong.hros.service.HrService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * @Description :
 * @Author: Liruilong
 * @Date: 2019/12/18 19:11
 */
 
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    HrService hrService;
    @Autowired
    CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
    @Autowired
    CustomUrlDecisionManager customUrlDecisionManager;
     @Autowired
    VerifyCodeFilter verifyCodeFilter ;
    @Autowired
    MyAuthenticationFailureHandler myAuthenticationFailureHandler;
 
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(hrService);
    }
    /**
     * @Author Liruilong
     * @Description  放行的請(qǐng)求路徑
     * @Date 19:25 2020/2/7
     * @Param [web]
     * @return void
     **/
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/auth/code","/login","/css/**","/js/**", "/index.html", "/img/**", "/fonts/**","/favicon.ico");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                //.anyRequest().authenticated()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        object.setAccessDecisionManager(customUrlDecisionManager);
                        object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
                        return object;
                    }
                })
                .and().formLogin().usernameParameter("username").passwordParameter("password") .loginProcessingUrl("/doLogin")
                .loginPage("/login")
                //登錄成功回調(diào)
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        Hr hr = (Hr) authentication.getPrincipal();
                        //密碼不回傳
                        hr.setPassword(null);
                        RespBean ok = RespBean.ok("登錄成功!", hr);
                        //將hr轉(zhuǎn)化為Sting
                        String s = new ObjectMapper().writeValueAsString(ok);
                        out.write(s);
                        out.flush();
                        out.close();
                    }
                })
                //登失敗回調(diào)
                .failureHandler(myAuthenticationFailureHandler)
                //相關(guān)的接口直接返回
                .permitAll()
                .and()
                .logout()
                //注銷登錄
                // .logoutSuccessUrl("")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest,
                                                HttpServletResponse httpServletResponse,
                                                Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(RespBean.ok("注銷成功!")));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()
                .and()
                .csrf().disable().exceptionHandling()
                //沒(méi)有認(rèn)證時(shí),在這里處理結(jié)果,不要重定向
                .authenticationEntryPoint(new AuthenticationEntryPoint() {
                    @Override
                    public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException authException) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        resp.setStatus(401);
                        PrintWriter out = resp.getWriter();
                        RespBean respBean = RespBean.error("訪問(wèn)失敗!");
                        if (authException instanceof InsufficientAuthenticationException) {
                            respBean.setMsg("請(qǐng)求失敗,請(qǐng)聯(lián)系管理員!");
                        }
                        out.write(new ObjectMapper().writeValueAsString(respBean));
                        out.flush();
                        out.close();
                    }
                });
    }
}
 
 

到此這篇關(guān)于Springboot+SpringSecurity實(shí)現(xiàn)圖片驗(yàn)證碼登錄的示例的文章就介紹到這了,更多相關(guān)Springboot SpringSecurity圖片驗(yàn)證碼登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 讓Java后臺(tái)MySQL數(shù)據(jù)庫(kù)能夠支持emoji表情的方法

    讓Java后臺(tái)MySQL數(shù)據(jù)庫(kù)能夠支持emoji表情的方法

    最近開(kāi)發(fā)的iOS項(xiàng)目因?yàn)樾枰脩粑谋镜拇鎯?chǔ),自然就遇到了emoji等表情符號(hào)如何被mysql DB支持的問(wèn)題。下面這篇文章主要介紹了關(guān)于讓Java后臺(tái)MySQL數(shù)據(jù)庫(kù)能夠支持emoji表情的方法,需要的朋友可以參考下。
    2017-03-03
  • java建立子類方法總結(jié)

    java建立子類方法總結(jié)

    在本篇文章里小編給大家分享了關(guān)于java建子類的步驟和方法,需要的朋友們跟著學(xué)習(xí)下。
    2019-05-05
  • SpringBoot?整合Mybatis-Plus并輸出SQL日志示例詳解

    SpringBoot?整合Mybatis-Plus并輸出SQL日志示例詳解

    這篇文章主要介紹了SpringBoot整合Mybatis-Plus并輸出SQL日志,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Jsoup解析HTML實(shí)例及文檔方法詳解

    Jsoup解析HTML實(shí)例及文檔方法詳解

    這篇文章主要介紹了Jsoup如何解析一個(gè)HTML文檔、從文件加載文檔、從URL加載Document等方法,對(duì)Jsoup常用方法做了詳細(xì)講解,最近提供了一個(gè)示例供大家參考 使用DOM方法來(lái)遍歷一個(gè)文檔 從元素抽取屬性,文本和HTML 獲取所有鏈接
    2013-11-11
  • Java中自動(dòng)裝箱、拆箱引起的耗時(shí)詳解

    Java中自動(dòng)裝箱、拆箱引起的耗時(shí)詳解

    這篇文章主要給大家介紹了關(guān)于Java中自動(dòng)裝箱、拆箱引起的耗時(shí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Kafka?Producer中的消息緩存模型圖解詳解

    Kafka?Producer中的消息緩存模型圖解詳解

    Kafka中消息是以Topic進(jìn)行分類的,生產(chǎn)者生產(chǎn)消息,消費(fèi)者消費(fèi)消息,都是面向Topic的,下面這篇文章主要給大家介紹了關(guān)于Kafka?Producer中消息緩存模型的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Springboot插件開(kāi)發(fā)實(shí)戰(zhàn)分享

    Springboot插件開(kāi)發(fā)實(shí)戰(zhàn)分享

    這篇文章主要介紹了Springboot插件開(kāi)發(fā)實(shí)戰(zhàn)分享,文章通過(guò)新建aop切面執(zhí)行類MonitorLogInterceptor展開(kāi)詳細(xì)的相關(guān)內(nèi)容,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • Spring如何通過(guò)注解引入外部資源(PropertySource?Value)

    Spring如何通過(guò)注解引入外部資源(PropertySource?Value)

    這篇文章主要為大家介紹了Spring通過(guò)注解@PropertySource和@Value引入外部資源的方法實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • springboot-mongodb的多數(shù)據(jù)源配置的方法步驟

    springboot-mongodb的多數(shù)據(jù)源配置的方法步驟

    這篇文章主要介紹了springboot-mongodb的多數(shù)據(jù)源配置的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 舉例講解Java中的多線程編程

    舉例講解Java中的多線程編程

    這篇文章主要介紹了舉例講解Java中的多線程編程,線程是Java學(xué)習(xí)中的重要知識(shí),需要的朋友可以參考下
    2015-09-09

最新評(píng)論