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

Spring Security 圖片驗(yàn)證碼功能的實(shí)例代碼

 更新時(shí)間:2018年03月05日 09:55:44   作者:奮斗的羊仔  
spring security是一系列的過濾器鏈,所以在這里驗(yàn)證碼也聲明為過濾器,加在過濾器鏈的 登錄過濾器之前,然后自定義一個(gè)異常類,來響應(yīng)驗(yàn)證碼的錯(cuò)誤信息.這篇文章主要介紹了Spring Security 圖片驗(yàn)證碼,需要的朋友可以參考下

驗(yàn)證碼邏輯

以前在項(xiàng)目中也做過驗(yàn)證碼,生成驗(yàn)證碼的代碼網(wǎng)上有很多,也有一些第三方的jar包也可以生成漂亮的驗(yàn)證碼。驗(yàn)證碼邏輯很簡單,就是在登錄頁放一個(gè)image標(biāo)簽,src指向一個(gè)controller,這個(gè)Controller返回把生成的圖片以輸出流返回給頁面,生成圖片的同時(shí)把圖片上的文本放在session,登錄的時(shí)候帶過來輸入的驗(yàn)證碼,從session中取出,兩者對(duì)比。這位老師講的用Spring Security集成驗(yàn)證碼,大體思路和我說的一樣,但更加規(guī)范和通用些。

spring security是一系列的過濾器鏈,所以在這里驗(yàn)證碼也聲明為過濾器,加在過濾器鏈的 登錄過濾器之前,然后自定義一個(gè)異常類,來響應(yīng)驗(yàn)證碼的錯(cuò)誤信息。

代碼結(jié)構(gòu):

驗(yàn)證碼代碼放在core項(xiàng)目,在browser項(xiàng)目做一下配置。

主要代碼:

1,ImageCode:

 首先是ImageCode類,封裝驗(yàn)證碼圖片、文本、過期時(shí)間

package com.imooc.security.core.validate.code;
import java.awt.image.BufferedImage;
import java.time.LocalDateTime;
import java.time.LocalTime;
/**
 * 驗(yàn)證碼
 * ClassName: ImageCode 
 * @Description: 驗(yàn)證碼
 * @author lihaoyang
 * @date 2018年3月1日
 */
public class ImageCode {
 private BufferedImage image;
 private String code;
 private LocalDateTime expireTime;//過期時(shí)間點(diǎn)
 /**
 * 
 * <p>Description: </p>
 * @param image
 * @param code
 * @param expireTn 多少秒過期
 */
 public ImageCode(BufferedImage image, String code, int expireTn) {
 super();
 this.image = image;
 this.code = code;
 //過期時(shí)間=當(dāng)前時(shí)間+過期秒數(shù) 
 this.expireTime = LocalDateTime.now().plusSeconds(expireTn);
 }
 public ImageCode(BufferedImage image, String code, LocalDateTime expireTime) {
 super();
 this.image = image;
 this.code = code;
 this.expireTime = expireTime;
 }
 /**
 * 驗(yàn)證碼是否過期
 * @Description: 驗(yàn)證碼是否過期
 * @param @return true 過期,false 沒過期
 * @return boolean true 過期,false 沒過期
 * @throws
 * @author lihaoyang
 * @date 2018年3月2日
 */
 public boolean isExpired(){
 return LocalDateTime.now().isAfter(expireTime);
 }
 public BufferedImage getImage() {
 return image;
 }
 public void setImage(BufferedImage image) {
 this.image = image;
 }
 public String getCode() {
 return code;
 }
 public void setCode(String code) {
 this.code = code;
 }
 public LocalDateTime getExpireTime() {
 return expireTime;
 }
 public void setExpireTime(LocalDateTime expireTime) {
 this.expireTime = expireTime;
 }
}

VerifyCode:生成驗(yàn)證碼的工具類,在這里http://www.cnblogs.com/lihaoyang/p/7131512.html 當(dāng)然也可以使用第三方j(luò)ar包,無所謂。

ValidateCodeException:封裝驗(yàn)證碼異常

/** 
 * @Title: ValidateCodeException.java
 * @Package com.imooc.security.core.validate.code
 * @Description: TODO
 * @author lihaoyang
 * @date 2018年3月2日
 */
package com.imooc.security.core.validate.code;
import org.springframework.security.core.AuthenticationException;
/**
 * ClassName: ValidateCodeException 
 * @Description: 驗(yàn)證碼錯(cuò)誤異常,繼承spring security的認(rèn)證異常
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ValidateCodeException extends AuthenticationException {
 /**
 * @Fields serialVersionUID : TODO
 */
 private static final long serialVersionUID = 1L;
 public ValidateCodeException(String msg) {
 super(msg);
 }
}

ValidateCodeFilter:驗(yàn)證碼過濾器

邏輯:繼承OncePerRequestFilter 保證過濾器每次只會(huì)被調(diào)用一次(不太清楚為什么),注入認(rèn)證失敗處理器,在驗(yàn)證失敗時(shí)調(diào)用。

package com.imooc.security.core.validate.code;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;
/**
 * 處理登錄驗(yàn)證碼過濾器
 * ClassName: ValidateCodeFilter 
 * @Description:
 * OncePerRequestFilter:spring提供的工具,保證過濾器每次只會(huì)被調(diào)用一次
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ValidateCodeFilter extends OncePerRequestFilter{
 //認(rèn)證失敗處理器
 private AuthenticationFailureHandler authenticationFailureHandler;
 //獲取session工具類
 private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
 @Override
 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  throws ServletException, IOException {
 //如果是 登錄請(qǐng)求 則執(zhí)行
 if(StringUtils.equals("/authentication/form", request.getRequestURI())
  &&StringUtils.equalsIgnoreCase(request.getMethod(), "post")){
  try {
  validate(new ServletWebRequest(request));
  } catch (ValidateCodeException e) {
  //調(diào)用錯(cuò)誤處理器,最終調(diào)用自己的
  authenticationFailureHandler.onAuthenticationFailure(request, response, e);
  return ;//結(jié)束方法,不再調(diào)用過濾器鏈
  }
 }
 //不是登錄請(qǐng)求,調(diào)用其它過濾器鏈
 filterChain.doFilter(request, response);
 }
 /**
 * 校驗(yàn)驗(yàn)證碼
 * @Description: 校驗(yàn)驗(yàn)證碼
 * @param @param request
 * @param @throws ServletRequestBindingException 
 * @return void 
 * @throws ValidateCodeException
 * @author lihaoyang
 * @date 2018年3月2日
 */
 private void validate(ServletWebRequest request) throws ServletRequestBindingException {
 //拿出session中的ImageCode對(duì)象
 ImageCode imageCodeInSession = (ImageCode) sessionStrategy.getAttribute(request, ValidateCodeController.SESSION_KEY);
 //拿出請(qǐng)求中的驗(yàn)證碼
 String imageCodeInRequest = ServletRequestUtils.getStringParameter(request.getRequest(), "imageCode");
 //校驗(yàn)
 if(StringUtils.isBlank(imageCodeInRequest)){
  throw new ValidateCodeException("驗(yàn)證碼不能為空");
 }
 if(imageCodeInSession == null){
  throw new ValidateCodeException("驗(yàn)證碼不存在,請(qǐng)刷新驗(yàn)證碼");
 }
 if(imageCodeInSession.isExpired()){
  //從session移除過期的驗(yàn)證碼
  sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);
  throw new ValidateCodeException("驗(yàn)證碼已過期,請(qǐng)刷新驗(yàn)證碼");
 }
 if(!StringUtils.equalsIgnoreCase(imageCodeInSession.getCode(), imageCodeInRequest)){
  throw new ValidateCodeException("驗(yàn)證碼錯(cuò)誤");
 }
 //驗(yàn)證通過,移除session中驗(yàn)證碼
 sessionStrategy.removeAttribute(request, ValidateCodeController.SESSION_KEY);
 }
 public AuthenticationFailureHandler getAuthenticationFailureHandler() {
 return authenticationFailureHandler;
 }
 public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
 this.authenticationFailureHandler = authenticationFailureHandler;
 }
}

ValidateCodeController:生成驗(yàn)證碼Control

package com.imooc.security.core.validate.code;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.ServletWebRequest;
/**
 * 驗(yàn)證碼Control
 * ClassName: ValidateCodeController 
 * @Description: TODO
 * @author lihaoyang
 * @date 2018年3月1日
 */
@RestController
public class ValidateCodeController {
 public static final String SESSION_KEY = "SESSION_KEY_IMAGE_CODE"; 
 //獲取session
 private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
 @GetMapping("/verifycode/image")
 public void createCode(HttpServletRequest request,HttpServletResponse response) throws IOException{
 ImageCode imageCode = createImageCode(request, response);
 sessionStrategy.setAttribute(new ServletWebRequest(request), SESSION_KEY, imageCode);
 ImageIO.write(imageCode.getImage(), "JPEG", response.getOutputStream());
 }
 private ImageCode createImageCode(HttpServletRequest request, HttpServletResponse response) {
 VerifyCode verifyCode = new VerifyCode();
 return new ImageCode(verifyCode.getImage(),verifyCode.getText(),60);
 }
}

BrowserSecurityConfig里進(jìn)行過濾器配置:

package com.imooc.security.browser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.imooc.security.core.properties.SecurityProperties;
import com.imooc.security.core.validate.code.ValidateCodeFilter;
@Configuration //這是一個(gè)配置
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter{
 //讀取用戶配置的登錄頁配置
 @Autowired
 private SecurityProperties securityProperties;
 //自定義的登錄成功后的處理器
 @Autowired
 private AuthenticationSuccessHandler imoocAuthenticationSuccessHandler;
 //自定義的認(rèn)證失敗后的處理器
 @Autowired
 private AuthenticationFailureHandler imoocAuthenticationFailureHandler;
 //注意是org.springframework.security.crypto.password.PasswordEncoder
 @Bean
 public PasswordEncoder passwordencoder(){
 //BCryptPasswordEncoder implements PasswordEncoder
 return new BCryptPasswordEncoder();
 }
 //版本二:可配置的登錄頁
 @Override
 protected void configure(HttpSecurity http) throws Exception {
 //驗(yàn)證碼過濾器
 ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
 //驗(yàn)證碼過濾器中使用自己的錯(cuò)誤處理
 validateCodeFilter.setAuthenticationFailureHandler(imoocAuthenticationFailureHandler);
 
 //實(shí)現(xiàn)需要認(rèn)證的接口跳轉(zhuǎn)表單登錄,安全=認(rèn)證+授權(quán)
 //http.httpBasic() //這個(gè)就是默認(rèn)的彈框認(rèn)證
 //
 http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)//把驗(yàn)證碼過濾器加載登錄過濾器前邊
  .formLogin() //表單認(rèn)證
  .loginPage("/authentication/require") //處理用戶認(rèn)證BrowserSecurityController
  //登錄過濾器UsernamePasswordAuthenticationFilter默認(rèn)登錄的url是"/login",在這能改
  .loginProcessingUrl("/authentication/form") 
  .successHandler(imoocAuthenticationSuccessHandler)//自定義的認(rèn)證后處理器
  .failureHandler(imoocAuthenticationFailureHandler) //登錄失敗后的處理
  .and()
  .authorizeRequests() //下邊的都是授權(quán)的配置
  // /authentication/require:處理登錄,securityProperties.getBrowser().getLoginPage():用戶配置的登錄頁
  .antMatchers("/authentication/require",
   securityProperties.getBrowser().getLoginPage(),//放過登錄頁不過濾,否則報(bào)錯(cuò)
   "/verifycode/image").permitAll() //驗(yàn)證碼
  .anyRequest() //任何請(qǐng)求
  .authenticated() //都需要身份認(rèn)證
  .and()
  .csrf().disable() //關(guān)閉csrf防護(hù)
  ; 
 }
}

登陸頁:登陸頁做的比較粗糙,其實(shí)驗(yàn)證碼可以在驗(yàn)證碼input失去焦點(diǎn)的時(shí)候做校驗(yàn),還可以做個(gè)點(diǎn)擊圖片刷新驗(yàn)證碼功能,這里就不做了。

<body>
 demo 登錄頁. <br>
 <form action="/authentication/form" method="post">
 <table>
  <tr>
  <td>用戶名:</td>
  <td><input type="text" name="username"/></td>
  <td></td>
  </tr>
  <tr>
  <td>密碼:</td>
  <td><input type="password" name="password"/></td>
  <td></td>
  </tr>
  <tr>
  <td>驗(yàn)證碼:</td>
  <td>
   <input width="100" type="text" name="imageCode"/>
  </td>
  <td>
   <img src="/verifycode/image"/>
  </td>
  </tr>
  <tr>
  <td colspan="2" align="right"><button type="submit">登錄</button></td>
  </tr>
 </table>
 </form>
 </body>

訪問 http://localhost:8080/demo-login.html:

響應(yīng)自定義的異常信息

大體功能已經(jīng)沒問題了。但是不夠通用,比如驗(yàn)證碼圖片的寬高、過期時(shí)間、過濾的url、驗(yàn)證碼成邏輯都是寫死的。這些可以做成活的,現(xiàn)在把驗(yàn)證碼做成一個(gè)過濾器的好處體現(xiàn)出來了。我們可以配置需要過濾的url,有時(shí)候可能不只是登陸頁需要驗(yàn)證碼,這樣更加通用。

1,通用性改造 之 驗(yàn)證碼基本參數(shù)可配

做成可配置的,那個(gè)應(yīng)用引用該模塊,他自己配置去,不配置就使用默認(rèn)配置。而且,配置既可以在請(qǐng)求url中聲明,也可以在應(yīng)用中聲明,老師的確是老師,代碼通用性真好!

想要實(shí)現(xiàn)的效果是,在application.properties里做這樣的配置:

#驗(yàn)證碼 圖片寬、高、字符個(gè)數(shù)
imooc.security.code.image.width = 100
imooc.security.code.image.height = 30
imooc.security.code.image.length = 6

然后就能控制驗(yàn)證碼的效果,因?yàn)轵?yàn)證碼還分圖片驗(yàn)證碼、短信驗(yàn)證碼,所以多做了一級(jí).code.image,這就用到了springboot的自定義配置文件,需要聲明對(duì)應(yīng)的java類:

需要在SecurityProperties里聲明code屬性:

package com.imooc.security.core.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
 * 自定義配置項(xiàng)
 * ClassName: SecurityProperties 
 * @Description: 自定義配置項(xiàng)
 * 這個(gè)類會(huì)讀取application.properties里所有以imooc.security開頭的配置項(xiàng)
 * 
 * imooc.security.browser.loginPage = /demo-login.html
 * 其中的browser的配置會(huì)讀取到BrowserProperties中去
 * 這是以點(diǎn)分割的,一級(jí)一級(jí)的和類的屬性對(duì)應(yīng)
 * @author lihaoyang
 * @date 2018年2月28日
 */
@ConfigurationProperties(prefix="imooc.security")
public class SecurityProperties {
 private BrowserProperties browser = new BrowserProperties();
 private ValidateCodeProperties code = new ValidateCodeProperties();
 public BrowserProperties getBrowser() {
 return browser;
 }
 public void setBrowser(BrowserProperties browser) {
 this.browser = browser;
 }
 public ValidateCodeProperties getCode() {
 return code;
 }
 public void setCode(ValidateCodeProperties code) {
 this.code = code;
 }
}

ValidateCodeProperties:

package com.imooc.security.core.properties;
/**
 * 驗(yàn)證碼配置
 * ClassName: ValidateCodeProperties 
 * @Description: 驗(yàn)證碼配置,驗(yàn)證碼有圖片驗(yàn)證碼、短信驗(yàn)證碼等,所以再包一層
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ValidateCodeProperties {
 //默認(rèn)配置
 private ImageCodeProperties image = new ImageCodeProperties();
 public ImageCodeProperties getImage() {
 return image;
 }
 public void setImage(ImageCodeProperties image) {
 this.image = image;
 }
}

ImageCodeProperties:

package com.imooc.security.core.properties;
/**
 * 圖片驗(yàn)證碼配置類
 * ClassName: ImageCodeProperties 
 * @Description: 圖片驗(yàn)證碼配置類
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ImageCodeProperties {
 //圖片寬
 private int width = 67;
 //圖片高
 private int height = 23;
 //驗(yàn)證碼字符個(gè)數(shù)
 private int length = 4;
 //過期時(shí)間
 private int expireIn = 60;
 public int getWidth() {
 return width;
 }
 public void setWidth(int width) {
 this.width = width;
 }
 public int getHeight() {
 return height;
 }
 public void setHeight(int height) {
 this.height = height;
 }
 public int getLength() {
 return length;
 }
 public void setLength(int length) {
 this.length = length;
 }
 public int getExpireIn() {
 return expireIn;
 }
 public void setExpireIn(int expireIn) {
 this.expireIn = expireIn;
 }
}

請(qǐng)求級(jí)的配置,如果請(qǐng)求里帶的有驗(yàn)證碼的參數(shù),就用請(qǐng)求里的:

在ValidateCodeController的createImageCode方法做控制,判斷請(qǐng)求參數(shù)是否有這些參數(shù),有的話,傳給驗(yàn)證碼生成類VerifyCode,在生成的時(shí)候就能動(dòng)態(tài)控制了。

private ImageCode createImageCode(HttpServletRequest request, HttpServletResponse response) {
 //先從request里讀取有沒有長、寬、字符個(gè)數(shù)參數(shù),有的話就用,沒有用默認(rèn)的
 int width = ServletRequestUtils.getIntParameter(request, "width",securityProperties.getCode().getImage().getWidth());
 
 int height = ServletRequestUtils.getIntParameter(request, "height",securityProperties.getCode().getImage().getHeight());
 
 int charLength = this.securityProperties.getCode().getImage().getLength();
 VerifyCode verifyCode = new VerifyCode(width,height,charLength);
 return new ImageCode(verifyCode.getImage(),verifyCode.getText(),this.securityProperties.getCode().getImage().getExpireIn());
 }

VerifyCode:

public VerifyCode(int w, int h, int charLength) {
 super();
 this.w = w;
 this.h = h;
 this.charLength = charLength;
 }

實(shí)驗(yàn):在demo項(xiàng)目做應(yīng)用級(jí)配置

登錄表單做請(qǐng)求級(jí)配置

<img src="/verifycode/image?width=200"/>

訪問:

長度為請(qǐng)求級(jí)帶的參數(shù)200,高為30,字符為配置的6個(gè)。

2,通用性改造 之 驗(yàn)證碼攔截的接口可配置

先要的效果就是再application.properties里能動(dòng)態(tài)配置需要攔截的接口:

ImageCodeProperties新增一個(gè)屬性:private String url; //攔截的url,來匹配上圖的配置。

核心,驗(yàn)證碼過濾器需要修改:

1,在攔截器里聲明一個(gè)set集合,用來存儲(chǔ)配置文件里配置的需要攔截的urls。

2,實(shí)現(xiàn)InitializingBean接口,目的: 在其他參數(shù)都組裝完畢的時(shí)候,初始化需要攔截的urls的值,重寫afterPropertiesSet方法來實(shí)現(xiàn)。

3,注入SecurityProperties,讀取配置文件

4,實(shí)例化AntPathMatcher工具類,這是一個(gè)匹配器

5,在browser項(xiàng)目的BrowserSecurityConfig里設(shè)置調(diào)用一下afterPropertiesSet方法。

6,在引用該模塊的demo項(xiàng)目的application.properties里配置要過濾的url

ValidateCodeFilter:

/**
 * 處理登錄驗(yàn)證碼過濾器
 * ClassName: ValidateCodeFilter 
 * @Description:
 * 繼承OncePerRequestFilter:spring提供的工具,保證過濾器每次只會(huì)被調(diào)用一次
 * 實(shí)現(xiàn) InitializingBean接口的目的:
 * 在其他參數(shù)都組裝完畢的時(shí)候,初始化需要攔截的urls的值
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean{
 //認(rèn)證失敗處理器
 private AuthenticationFailureHandler authenticationFailureHandler;
 //獲取session工具類
 private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
 //需要攔截的url集合
 private Set<String> urls = new HashSet<>();
 //讀取配置
 private SecurityProperties securityProperties;
 //spring工具類
 private AntPathMatcher antPathMatcher = new AntPathMatcher();
 @Override
 public void afterPropertiesSet() throws ServletException {
 super.afterPropertiesSet();
 //讀取配置的攔截的urls
 String[] configUrls = StringUtils.splitByWholeSeparatorPreserveAllTokens(securityProperties.getCode().getImage().getUrl(), ",");
 for (String configUrl : configUrls) {
  urls.add(configUrl);
 }
 //登錄的請(qǐng)求一定攔截
 urls.add("/authentication/form");
 }
 @Override
 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  throws ServletException, IOException {
 /**
  * 可配置的驗(yàn)證碼校驗(yàn)
  * 判斷請(qǐng)求的url和配置的是否有匹配的,匹配上了就過濾
  */
 boolean action = false;
 for(String url:urls){
  if(antPathMatcher.match(url, request.getRequestURI())){
  action = true;
  }
 }
 if(action){
  try {
  validate(new ServletWebRequest(request));
  } catch (ValidateCodeException e) {
  //調(diào)用錯(cuò)誤處理器,最終調(diào)用自己的
  authenticationFailureHandler.onAuthenticationFailure(request, response, e);
  return ;//結(jié)束方法,不再調(diào)用過濾器鏈
  }
 }
 //不是登錄請(qǐng)求,調(diào)用其它過濾器鏈
 filterChain.doFilter(request, response);
 }
 //省略無關(guān)代碼,,,
}

BrowserSecurityConfig:

配置url:

#驗(yàn)證碼攔截的接口配置
imooc.security.code.image.url = /user,/user/*

測試:/user  /user/1 被攔截了

訪問登錄頁,不寫驗(yàn)證碼:

和預(yù)期一致。至此,動(dòng)態(tài)配置攔截接口完成

3,驗(yàn)證碼的生成邏輯可配置

 寫的比較好的程序,一般都開放接口,可以讓用戶去自定義實(shí)現(xiàn),如果不實(shí)現(xiàn)就用默認(rèn)的實(shí)現(xiàn),下面來做這件事,使驗(yàn)證碼的生成可以自己實(shí)現(xiàn)。如果要想把驗(yàn)證碼的生成邏輯做成可配置的,就不能只寫一個(gè)圖片驗(yàn)證碼生成器的類了,需要把驗(yàn)證碼生成提取成一個(gè)接口ValidateCodeGenerator,一個(gè)生成驗(yàn)證碼的方法generator()。因?yàn)轵?yàn)證碼還有圖片驗(yàn)證碼、短信驗(yàn)證碼等,這樣,我們?cè)谧约旱尿?yàn)證模塊里做一個(gè)默認(rèn)的實(shí)現(xiàn),如圖片驗(yàn)證碼的實(shí)現(xiàn)ImageCodeGenerator,在ImageCodeGenerator里我們不在該類上加@Component注解。然后使用寫一個(gè)驗(yàn)證碼bean的配置類ValidateCodeBeanConfig,這個(gè)配置類配置各種需要的驗(yàn)證碼實(shí)現(xiàn)類bean如圖片驗(yàn)證碼實(shí)現(xiàn)imageCodeGenerator、短信驗(yàn)證碼等,他們返回類型都是ValidateCodeGenerator,使用@ConditionalOnMissingBean(name="imageCodeGenerator")注解,可以判斷如果當(dāng)前spring容器有名字為imageCodeGenerator的bean時(shí),就使用,沒有的話再配置,這樣如果別人引用了你的該模塊,如果別人自己實(shí)現(xiàn)了驗(yàn)證碼生成ValidateCodeGenerator接口,他們配置了實(shí)現(xiàn)類的name為imageCodeGenerator,就用他們自己的實(shí)現(xiàn),這樣就做到了程序的可擴(kuò)展性。

 主要代碼:

代碼生成器接口ValidateCodeGenerator:

package com.imooc.security.core.validate.code;
import org.springframework.web.context.request.ServletWebRequest;
/**
 * 驗(yàn)證碼生成接口
 * ClassName: ValidateCodeGenerator 
 * @Description: TODO
 * @author lihaoyang
 * @date 2018年3月2日
 */
public interface ValidateCodeGenerator {

 /**
 * 圖片驗(yàn)證碼生成接口
 * @Description: TODO
 * @param @param request
 * @param @return 
 * @return ImageCode 
 * @throws
 * @author lihaoyang
 * @date 2018年3月2日
 */
 ImageCode generator(ServletWebRequest request);
}

圖片驗(yàn)證碼生成器實(shí)現(xiàn)ImageCodeGenerator:

package com.imooc.security.core.validate.code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import com.imooc.security.core.properties.SecurityProperties;
/**
 * 圖片驗(yàn)證碼生成類
 * ClassName: ImageCodeGenerator 
 * @Description: TODO
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class ImageCodeGenerator implements ValidateCodeGenerator {
 @Autowired
 private SecurityProperties securityProperties;
 @Override
 public ImageCode generator(ServletWebRequest request) {
 //先從request里讀取有沒有長、寬、字符個(gè)數(shù)參數(shù),有的話就用,沒有用默認(rèn)的
 int width = ServletRequestUtils.getIntParameter(request.getRequest(), "width",securityProperties.getCode().getImage().getWidth());
 int height = ServletRequestUtils.getIntParameter(request.getRequest(), "height",securityProperties.getCode().getImage().getHeight());
 int charLength = this.securityProperties.getCode().getImage().getLength();
 VerifyCode verifyCode = new VerifyCode(width,height,charLength);
 return new ImageCode(verifyCode.getImage(),verifyCode.getText(),this.securityProperties.getCode().getImage().getExpireIn());
 }
 public SecurityProperties getSecurityProperties() {
 return securityProperties;
 }
 public void setSecurityProperties(SecurityProperties securityProperties) {
 this.securityProperties = securityProperties;
 }
}

ValidateCodeBeanConfig:

package com.imooc.security.core.validate.code;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.imooc.security.core.properties.SecurityProperties;
/**
 * 配置驗(yàn)證碼生成接口ValidateCodeGenerator的實(shí)際實(shí)現(xiàn)類的Bean
 * ClassName: ValidateCodeBeanConfig 
 * @Description: 
 * 配置驗(yàn)證碼生成接口ValidateCodeGenerator的實(shí)際實(shí)現(xiàn)類的Bean
 * 如圖片驗(yàn)證碼的實(shí)現(xiàn)、短信驗(yàn)證碼的實(shí)現(xiàn)
 * @author lihaoyang
 * @date 2018年3月5日
 */
@Configuration
public class ValidateCodeBeanConfig {
 @Autowired
 private SecurityProperties securityProperties;
 /**
 * @Description: 
 * @ConditionalOnMissingBean注解意思是當(dāng)spring容器不存在imageCodeGenerator時(shí)才給配置一個(gè)該bean
 * 作用是使程序更具可擴(kuò)展性,該配置類是配置在core模塊,這就意味著,如果引用該模塊的項(xiàng)目
 * 如果有一個(gè)自己的實(shí)現(xiàn),實(shí)現(xiàn)了ValidateCodeGenerator接口,定義了自己的實(shí)現(xiàn),名字也叫imageCodeGenerator時(shí),
 * 就用應(yīng)用級(jí)別的實(shí)現(xiàn),沒有的話就用這個(gè)默認(rèn)實(shí)現(xiàn)。
 * @param @return 
 * @return ValidateCodeGenerator 
 * @throws
 * @author lihaoyang
 * @date 2018年3月5日
 */
 @Bean
 @ConditionalOnMissingBean(name="imageCodeGenerator") 
 public ValidateCodeGenerator imageCodeGenerator(){ 
 ImageCodeGenerator codeGenerator = new ImageCodeGenerator();
 codeGenerator.setSecurityProperties(securityProperties);
 return codeGenerator;
 }
}

這樣,如果哪個(gè)模塊引用了這個(gè)驗(yàn)證碼模塊,他自定義了實(shí)現(xiàn),如:

package com.imooc.code;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletWebRequest;
import com.imooc.security.core.validate.code.ImageCode;
import com.imooc.security.core.validate.code.ValidateCodeGenerator;
@Component("imageCodeGenerator")
public class DemoImageCodeGenerator implements ValidateCodeGenerator {
 @Override
 public ImageCode generator(ServletWebRequest request) {
 System.err.println("demo項(xiàng)目實(shí)現(xiàn)的生成驗(yàn)證碼,,,");
 return null;
 }
}

這樣ValidateCodeBeanConfig在配置驗(yàn)證碼bean時(shí),就會(huì)使用使用者自定義的實(shí)現(xiàn)。

完整代碼放在了github:https://github.com/lhy1234/spring-security

總結(jié)

以上所述是小編給大家介紹的Spring Security 圖片驗(yàn)證碼功能的實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java基于NIO實(shí)現(xiàn)聊天室功能

    Java基于NIO實(shí)現(xiàn)聊天室功能

    這篇文章主要為大家詳細(xì)介紹了Java基于NIO實(shí)現(xiàn)聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • SpringCloud Ribbon與OpenFeign詳解如何實(shí)現(xiàn)服務(wù)調(diào)用

    SpringCloud Ribbon與OpenFeign詳解如何實(shí)現(xiàn)服務(wù)調(diào)用

    這篇文章主要介紹了SpringCloud Ribbon與OpenFeign實(shí)現(xiàn)服務(wù)調(diào)用的過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • Spring?Boot和Vue前后端分離項(xiàng)目架構(gòu)的全過程

    Spring?Boot和Vue前后端分離項(xiàng)目架構(gòu)的全過程

    前后端分離是目前互聯(lián)網(wǎng)開發(fā)中比較廣泛使用的開發(fā)模式,主要是將前端和后端的項(xiàng)目業(yè)務(wù)進(jìn)行分離,下面這篇文章主要給大家介紹了關(guān)于Spring?Boot和Vue前后端分離項(xiàng)目架構(gòu)的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • 利用session實(shí)現(xiàn)簡單購物車功能

    利用session實(shí)現(xiàn)簡單購物車功能

    這篇文章主要為大家詳細(xì)介紹了利用session實(shí)現(xiàn)簡單購物車功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • java 實(shí)現(xiàn)當(dāng)前時(shí)間加減30分鐘的時(shí)間代碼

    java 實(shí)現(xiàn)當(dāng)前時(shí)間加減30分鐘的時(shí)間代碼

    這篇文章主要介紹了java 實(shí)現(xiàn)當(dāng)前時(shí)間加減30分鐘的時(shí)間代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • SpringBoot中mapper.xml文件存放的兩種實(shí)現(xiàn)位置

    SpringBoot中mapper.xml文件存放的兩種實(shí)現(xiàn)位置

    這篇文章主要介紹了SpringBoot中mapper.xml文件存放的兩種實(shí)現(xiàn)位置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • java簡單實(shí)現(xiàn)計(jì)算器

    java簡單實(shí)現(xiàn)計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了java簡單實(shí)現(xiàn)計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • SpringCloud微服務(wù)開發(fā)基于RocketMQ實(shí)現(xiàn)分布式事務(wù)管理詳解

    SpringCloud微服務(wù)開發(fā)基于RocketMQ實(shí)現(xiàn)分布式事務(wù)管理詳解

    分布式事務(wù)是在微服務(wù)開發(fā)中經(jīng)常會(huì)遇到的一個(gè)問題,之前的文章中我們已經(jīng)實(shí)現(xiàn)了利用Seata來實(shí)現(xiàn)強(qiáng)一致性事務(wù),其實(shí)還有一種廣為人知的方案就是利用消息隊(duì)列來實(shí)現(xiàn)分布式事務(wù),保證數(shù)據(jù)的最終一致性,也就是我們常說的柔性事務(wù)
    2022-09-09
  • 淺析Java數(shù)據(jù)庫操作工具包jOOQ的使用

    淺析Java數(shù)據(jù)庫操作工具包jOOQ的使用

    jOOQ?是一個(gè)輕量級(jí)的?Java?ORM(對(duì)象關(guān)系映射)框架,可用來構(gòu)建復(fù)雜的?SQL?查詢,這篇文章主要來和大家介紹一下jOOQ的使用,需要的可以參考下
    2024-04-04
  • SpringBoot詳解Banner的使用

    SpringBoot詳解Banner的使用

    這篇文章主要介紹了超個(gè)性修改SpringBoot項(xiàng)目的啟動(dòng)banner的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評(píng)論