Spring Security添加驗(yàn)證碼的兩種方式小結(jié)
一、自定義認(rèn)證邏輯
生成驗(yàn)證碼工具
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
添加Kaptcha配置
@Configuration public class KaptchaConfig { @Bean Producer kaptcha() { Properties properties = new Properties(); properties.setProperty("kaptcha.image.width", "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; } }
生成驗(yàn)證碼文本,放入HttpSession中
根據(jù)驗(yàn)證碼文本生成圖片 通過(guò)IO流寫(xiě)出到前端。
@RestController public class LoginController { @Autowired Producer producer; @GetMapping("/vc.jpg") public void getVerifyCode(HttpServletResponse resp, HttpSession session) throws IOException { resp.setContentType("image/jpeg"); String text = producer.createText(); session.setAttribute("kaptcha", text); BufferedImage image = producer.createImage(text); try(ServletOutputStream out = resp.getOutputStream()) { ImageIO.write(image, "jpg", out); } } @RequestMapping("/index") public String index() { return "login success"; } @RequestMapping("/hello") public String hello() { return "hello spring security"; } }
form表單
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登錄</title> <link rel="external nofollow" rel="stylesheet" id="bootstrap-css"> <script src="http://maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script> <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> </head> <style> #login .container #login-row #login-column #login-box { border: 1px solid #9C9C9C; background-color: #EAEAEA; } </style> <body> <div id="login"> <div class="container"> <div id="login-row" class="row justify-content-center align-items-center"> <div id="login-column" class="col-md-6"> <div id="login-box" class="col-md-12"> <form id="login-form" class="form" action="/doLogin" method="post"> <h3 class="text-center text-info">登錄</h3> <div th:text="${SPRING_SECURITY_LAST_EXCEPTION}"></div> <div class="form-group"> <label for="username" class="text-info">用戶(hù)名:</label><br> <input type="text" name="uname" id="username" class="form-control"> </div> <div class="form-group"> <label for="password" class="text-info">密碼:</label><br> <input type="text" name="passwd" id="password" class="form-control"> </div> <div class="form-group"> <label for="kaptcha" class="text-info">驗(yàn)證碼:</label><br> <input type="text" name="kaptcha" id="kaptcha" class="form-control"> <img src="/vc.jpg" alt=""> </div> <div class="form-group"> <input type="submit" name="submit" class="btn btn-info btn-md" value="登錄"> </div> </form> </div> </div> </div> </div> </div> </body>
驗(yàn)證碼圖片地址為我們?cè)贑ontroller中定義的驗(yàn)證碼接口地址。
身份認(rèn)證是AuthenticationProvider的authenticate方法完成,因此驗(yàn)證碼可以在此之前完成:
public class KaptchaAuthenticationProvider extends DaoAuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String kaptcha = req.getParameter("kaptcha"); String sessionKaptcha = (String) req.getSession().getAttribute("kaptcha"); if (kaptcha != null && sessionKaptcha != null && kaptcha.equalsIgnoreCase(sessionKaptcha)) { return super.authenticate(authentication); } throw new AuthenticationServiceException("驗(yàn)證碼輸入錯(cuò)誤"); } }
配置AuthenticationManager:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean AuthenticationProvider kaptchaAuthenticationProvider() { InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(User.builder() .username("xiepanapn").password("{noop}123").roles("admin").build()); KaptchaAuthenticationProvider provider = new KaptchaAuthenticationProvider(); provider.setUserDetailsService(users); return provider; } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { ProviderManager manager = new ProviderManager(kaptchaAuthenticationProvider()); return manager; } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/vc.jpg").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/mylogin.html") .loginProcessingUrl("/doLogin") .defaultSuccessUrl("/index.html") .failureForwardUrl("/mylogin.html") .usernameParameter("uname") .passwordParameter("passwd") .permitAll() .and() .csrf().disable(); } }
- 配置UserDetailsService提供的數(shù)據(jù)源
- 提供AuthenticationProvider實(shí)例并配置UserDetailsService
- 重寫(xiě)authenticationManagerBean方法提供一個(gè)自己的ProviderManager并自定義AuthenticationManager實(shí)例。
二、自定義過(guò)濾器
LoginFilter繼承UsernamePasswordAuthenticationFilter 重寫(xiě)attemptAuthentication方法:
public class LoginFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if (!request.getMethod().equals("POST")) { throw new AuthenticationServiceException( "Authentication method not supported: " + request.getMethod()); } String kaptcha = request.getParameter("kaptcha"); String sessionKaptcha = (String) request.getSession().getAttribute("kaptcha"); if (!StringUtils.isEmpty(kaptcha) && !StringUtils.isEmpty(sessionKaptcha) && kaptcha.equalsIgnoreCase(sessionKaptcha)) { return super.attemptAuthentication(request, response); } throw new AuthenticationServiceException("驗(yàn)證碼輸入錯(cuò)誤"); } }
在SecurityConfig中配置LoginFilter
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("javaboy") .password("{noop}123") .roles("admin"); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean LoginFilter loginFilter() throws Exception { LoginFilter loginFilter = new LoginFilter(); loginFilter.setFilterProcessesUrl("/doLogin"); loginFilter.setAuthenticationManager(authenticationManagerBean()); loginFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/hello")); loginFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/mylogin.html")); return loginFilter; } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/vc.jpg").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/mylogin.html") .permitAll() .and() .csrf().disable(); http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class); } }
顯然第二種比較簡(jiǎn)單
總結(jié)
到此這篇關(guān)于Spring Security添加驗(yàn)證碼的兩種方式的文章就介紹到這了,更多相關(guān)Spring Security添加驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Security OAuth2集成短信驗(yàn)證碼登錄以及第三方登錄
- Spring Security Oauth2.0 實(shí)現(xiàn)短信驗(yàn)證碼登錄示例
- Spring Security登錄添加驗(yàn)證碼的實(shí)現(xiàn)過(guò)程
- SpringBoot + SpringSecurity 短信驗(yàn)證碼登錄功能實(shí)現(xiàn)
- SpringBoot結(jié)合SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能
- Spring Security 圖片驗(yàn)證碼功能的實(shí)例代碼
- SpringBoot+Security 發(fā)送短信驗(yàn)證碼的實(shí)現(xiàn)
- Spring Security 實(shí)現(xiàn)短信驗(yàn)證碼登錄功能
- SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能的實(shí)例代碼
- Spring Security實(shí)現(xiàn)驗(yàn)證碼登錄功能
相關(guān)文章
Java使用Catcher捕獲異常的實(shí)現(xiàn)
本文主要介紹了Java使用Catcher捕獲異常的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05解析使用jdbc,hibernate處理clob/blob字段的詳解
本篇是對(duì)使用jdbc,hibernate處理clob/blob字段進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Java設(shè)計(jì)模式之構(gòu)建者模式知識(shí)總結(jié)
這幾天剛好在復(fù)習(xí)Java的設(shè)計(jì)模式,今天就給小伙伴們?nèi)婵偨Y(jié)一下開(kāi)發(fā)中最常用的設(shè)計(jì)模式-建造者模式的相關(guān)知識(shí),里面有很詳細(xì)的代碼示例及注釋哦,需要的朋友可以參考下2021-05-05詳解java倒計(jì)時(shí)三種簡(jiǎn)單實(shí)現(xiàn)方式
這篇文章主要介紹了詳解java倒計(jì)時(shí)三種簡(jiǎn)單實(shí)現(xiàn)方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Java 比較接口comparable與comparator區(qū)別解析
這篇文章主要介紹了Java 比較接口comparable與comparator區(qū)別解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10解讀java?try?catch?異常后還會(huì)繼續(xù)執(zhí)行嗎
這篇文章主要介紹了解讀java?try?catch?異常后還會(huì)不會(huì)繼續(xù)執(zhí)行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11