欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Security 图片验证码功能的实例代码

程序员文章站 2022-06-21 15:59:23
验证码逻辑 以前在项目中也做过验证码,生成验证码的代码网上有很多,也有一些第三方的jar包也可以生成漂亮的验证码。验证码逻辑很简单,就是在登录页放一个image标签,sr...

验证码逻辑

以前在项目中也做过验证码,生成验证码的代码网上有很多,也有一些第三方的jar包也可以生成漂亮的验证码。验证码逻辑很简单,就是在登录页放一个image标签,src指向一个controller,这个controller返回把生成的图片以输出流返回给页面,生成图片的同时把图片上的文本放在session,登录的时候带过来输入的验证码,从session中取出,两者对比。这位老师讲的用spring security集成验证码,大体思路和我说的一样,但更加规范和通用些。

spring security是一系列的过滤器链,所以在这里验证码也声明为过滤器,加在过滤器链的 登录过滤器之前,然后自定义一个异常类,来响应验证码的错误信息。

Spring Security 图片验证码功能的实例代码

代码结构:

验证码代码放在core项目,在browser项目做一下配置。

Spring Security 图片验证码功能的实例代码

主要代码:

1,imagecode:

 首先是imagecode类,封装验证码图片、文本、过期时间

package com.imooc.security.core.validate.code;
import java.awt.image.bufferedimage;
import java.time.localdatetime;
import java.time.localtime;
/**
 * 验证码
 * classname: imagecode 
 * @description: 验证码
 * @author lihaoyang
 * @date 2018年3月1日
 */
public class imagecode {
 private bufferedimage image;
 private string code;
 private localdatetime expiretime;//过期时间点
 /**
 * 
 * <p>description: </p>
 * @param image
 * @param code
 * @param expiretn 多少秒过期
 */
 public imagecode(bufferedimage image, string code, int expiretn) {
 super();
 this.image = image;
 this.code = code;
 //过期时间=当前时间+过期秒数 
 this.expiretime = localdatetime.now().plusseconds(expiretn);
 }
 public imagecode(bufferedimage image, string code, localdatetime expiretime) {
 super();
 this.image = image;
 this.code = code;
 this.expiretime = expiretime;
 }
 /**
 * 验证码是否过期
 * @description: 验证码是否过期
 * @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:生成验证码的工具类,在这里 当然也可以使用第三方jar包,无所谓。

validatecodeexception:封装验证码异常

/** 
 * @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: 验证码错误异常,继承spring security的认证异常
 * @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:验证码过滤器

逻辑:继承onceperrequestfilter 保证过滤器每次只会被调用一次(不太清楚为什么),注入认证失败处理器,在验证失败时调用。

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;
/**
 * 处理登录验证码过滤器
 * classname: validatecodefilter 
 * @description:
 * onceperrequestfilter:spring提供的工具,保证过滤器每次只会被调用一次
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class validatecodefilter extends onceperrequestfilter{
 //认证失败处理器
 private authenticationfailurehandler authenticationfailurehandler;
 //获取session工具类
 private sessionstrategy sessionstrategy = new httpsessionsessionstrategy();
 @override
 protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain)
  throws servletexception, ioexception {
 //如果是 登录请求 则执行
 if(stringutils.equals("/authentication/form", request.getrequesturi())
  &&stringutils.equalsignorecase(request.getmethod(), "post")){
  try {
  validate(new servletwebrequest(request));
  } catch (validatecodeexception e) {
  //调用错误处理器,最终调用自己的
  authenticationfailurehandler.onauthenticationfailure(request, response, e);
  return ;//结束方法,不再调用过滤器链
  }
 }
 //不是登录请求,调用其它过滤器链
 filterchain.dofilter(request, response);
 }
 /**
 * 校验验证码
 * @description: 校验验证码
 * @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对象
 imagecode imagecodeinsession = (imagecode) sessionstrategy.getattribute(request, validatecodecontroller.session_key);
 //拿出请求中的验证码
 string imagecodeinrequest = servletrequestutils.getstringparameter(request.getrequest(), "imagecode");
 //校验
 if(stringutils.isblank(imagecodeinrequest)){
  throw new validatecodeexception("验证码不能为空");
 }
 if(imagecodeinsession == null){
  throw new validatecodeexception("验证码不存在,请刷新验证码");
 }
 if(imagecodeinsession.isexpired()){
  //从session移除过期的验证码
  sessionstrategy.removeattribute(request, validatecodecontroller.session_key);
  throw new validatecodeexception("验证码已过期,请刷新验证码");
 }
 if(!stringutils.equalsignorecase(imagecodeinsession.getcode(), imagecodeinrequest)){
  throw new validatecodeexception("验证码错误");
 }
 //验证通过,移除session中验证码
 sessionstrategy.removeattribute(request, validatecodecontroller.session_key);
 }
 public authenticationfailurehandler getauthenticationfailurehandler() {
 return authenticationfailurehandler;
 }
 public void setauthenticationfailurehandler(authenticationfailurehandler authenticationfailurehandler) {
 this.authenticationfailurehandler = authenticationfailurehandler;
 }
}

validatecodecontroller:生成验证码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;
/**
 * 验证码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里进行过滤器配置:

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 //这是一个配置
public class browsersecurityconfig extends websecurityconfigureradapter{
 //读取用户配置的登录页配置
 @autowired
 private securityproperties securityproperties;
 //自定义的登录成功后的处理器
 @autowired
 private authenticationsuccesshandler imoocauthenticationsuccesshandler;
 //自定义的认证失败后的处理器
 @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 {
 //验证码过滤器
 validatecodefilter validatecodefilter = new validatecodefilter();
 //验证码过滤器中使用自己的错误处理
 validatecodefilter.setauthenticationfailurehandler(imoocauthenticationfailurehandler);
 
 //实现需要认证的接口跳转表单登录,安全=认证+授权
 //http.httpbasic() //这个就是默认的弹框认证
 //
 http.addfilterbefore(validatecodefilter, usernamepasswordauthenticationfilter.class)//把验证码过滤器加载登录过滤器前边
  .formlogin() //表单认证
  .loginpage("/authentication/require") //处理用户认证browsersecuritycontroller
  //登录过滤器usernamepasswordauthenticationfilter默认登录的url是"/login",在这能改
  .loginprocessingurl("/authentication/form") 
  .successhandler(imoocauthenticationsuccesshandler)//自定义的认证后处理器
  .failurehandler(imoocauthenticationfailurehandler) //登录失败后的处理
  .and()
  .authorizerequests() //下边的都是授权的配置
  // /authentication/require:处理登录,securityproperties.getbrowser().getloginpage():用户配置的登录页
  .antmatchers("/authentication/require",
   securityproperties.getbrowser().getloginpage(),//放过登录页不过滤,否则报错
   "/verifycode/image").permitall() //验证码
  .anyrequest() //任何请求
  .authenticated() //都需要身份认证
  .and()
  .csrf().disable() //关闭csrf防护
  ; 
 }
}

登陆页:登陆页做的比较粗糙,其实验证码可以在验证码input失去焦点的时候做校验,还可以做个点击图片刷新验证码功能,这里就不做了。

<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>验证码:</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>

访问 :

Spring Security 图片验证码功能的实例代码

响应自定义的异常信息

Spring Security 图片验证码功能的实例代码

大体功能已经没问题了。但是不够通用,比如验证码图片的宽高、过期时间、过滤的url、验证码成逻辑都是写死的。这些可以做成活的,现在把验证码做成一个过滤器的好处体现出来了。我们可以配置需要过滤的url,有时候可能不只是登陆页需要验证码,这样更加通用。

1,通用性改造 之 验证码基本参数可配

做成可配置的,那个应用引用该模块,他自己配置去,不配置就使用默认配置。而且,配置既可以在请求url中声明,也可以在应用中声明,老师的确是老师,代码通用性真好!

Spring Security 图片验证码功能的实例代码

想要实现的效果是,在application.properties里做这样的配置:

#验证码 图片宽、高、字符个数
imooc.security.code.image.width = 100
imooc.security.code.image.height = 30
imooc.security.code.image.length = 6

然后就能控制验证码的效果,因为验证码还分图片验证码、短信验证码,所以多做了一级.code.image,这就用到了springboot的自定义配置文件,需要声明对应的java类:

Spring Security 图片验证码功能的实例代码

需要在securityproperties里声明code属性:

package com.imooc.security.core.properties;
import org.springframework.boot.context.properties.configurationproperties;
import org.springframework.context.annotation.configuration;
/**
 * 自定义配置项
 * classname: securityproperties 
 * @description: 自定义配置项
 * 这个类会读取application.properties里所有以imooc.security开头的配置项
 * 
 * imooc.security.browser.loginpage = /demo-login.html
 * 其中的browser的配置会读取到browserproperties中去
 * 这是以点分割的,一级一级的和类的属性对应
 * @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;
/**
 * 验证码配置
 * classname: validatecodeproperties 
 * @description: 验证码配置,验证码有图片验证码、短信验证码等,所以再包一层
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class validatecodeproperties {
 //默认配置
 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;
/**
 * 图片验证码配置类
 * classname: imagecodeproperties 
 * @description: 图片验证码配置类
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class imagecodeproperties {
 //图片宽
 private int width = 67;
 //图片高
 private int height = 23;
 //验证码字符个数
 private int length = 4;
 //过期时间
 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;
 }
}

请求级的配置,如果请求里带的有验证码的参数,就用请求里的:

Spring Security 图片验证码功能的实例代码

在validatecodecontroller的createimagecode方法做控制,判断请求参数是否有这些参数,有的话,传给验证码生成类verifycode,在生成的时候就能动态控制了。

private imagecode createimagecode(httpservletrequest request, httpservletresponse response) {
 //先从request里读取有没有长、宽、字符个数参数,有的话就用,没有用默认的
 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;
 }

实验:在demo项目做应用级配置

Spring Security 图片验证码功能的实例代码

登录表单做请求级配置

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

访问:

Spring Security 图片验证码功能的实例代码

长度为请求级带的参数200,高为30,字符为配置的6个。

2,通用性改造 之 验证码拦截的接口可配置

先要的效果就是再application.properties里能动态配置需要拦截的接口:

Spring Security 图片验证码功能的实例代码

imagecodeproperties新增一个属性:private string url; //拦截的url,来匹配上图的配置。

核心,验证码过滤器需要修改:

1,在拦截器里声明一个set集合,用来存储配置文件里配置的需要拦截的urls。

2,实现initializingbean接口,目的: 在其他参数都组装完毕的时候,初始化需要拦截的urls的值,重写afterpropertiesset方法来实现。

3,注入securityproperties,读取配置文件

4,实例化antpathmatcher工具类,这是一个匹配器

5,在browser项目的browsersecurityconfig里设置调用一下afterpropertiesset方法。

6,在引用该模块的demo项目的application.properties里配置要过滤的url

validatecodefilter:

/**
 * 处理登录验证码过滤器
 * classname: validatecodefilter 
 * @description:
 * 继承onceperrequestfilter:spring提供的工具,保证过滤器每次只会被调用一次
 * 实现 initializingbean接口的目的:
 * 在其他参数都组装完毕的时候,初始化需要拦截的urls的值
 * @author lihaoyang
 * @date 2018年3月2日
 */
public class validatecodefilter extends onceperrequestfilter implements initializingbean{
 //认证失败处理器
 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);
 }
 //登录的请求一定拦截
 urls.add("/authentication/form");
 }
 @override
 protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain)
  throws servletexception, ioexception {
 /**
  * 可配置的验证码校验
  * 判断请求的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) {
  //调用错误处理器,最终调用自己的
  authenticationfailurehandler.onauthenticationfailure(request, response, e);
  return ;//结束方法,不再调用过滤器链
  }
 }
 //不是登录请求,调用其它过滤器链
 filterchain.dofilter(request, response);
 }
 //省略无关代码,,,
}

browsersecurityconfig:

Spring Security 图片验证码功能的实例代码

配置url:

#验证码拦截的接口配置
imooc.security.code.image.url = /user,/user/*

测试:/user  /user/1 被拦截了

Spring Security 图片验证码功能的实例代码

Spring Security 图片验证码功能的实例代码

访问登录页,不写验证码:

Spring Security 图片验证码功能的实例代码

和预期一致。至此,动态配置拦截接口完成

3,验证码的生成逻辑可配置

 写的比较好的程序,一般都开放接口,可以让用户去自定义实现,如果不实现就用默认的实现,下面来做这件事,使验证码的生成可以自己实现。如果要想把验证码的生成逻辑做成可配置的,就不能只写一个图片验证码生成器的类了,需要把验证码生成提取成一个接口validatecodegenerator,一个生成验证码的方法generator()。因为验证码还有图片验证码、短信验证码等,这样,我们在自己的验证模块里做一个默认的实现,如图片验证码的实现imagecodegenerator,在imagecodegenerator里我们不在该类上加@component注解。然后使用写一个验证码bean的配置类validatecodebeanconfig,这个配置类配置各种需要的验证码实现类bean如图片验证码实现imagecodegenerator、短信验证码等,他们返回类型都是validatecodegenerator,使用@conditionalonmissingbean(name="imagecodegenerator")注解,可以判断如果当前spring容器有名字为imagecodegenerator的bean时,就使用,没有的话再配置,这样如果别人引用了你的该模块,如果别人自己实现了验证码生成validatecodegenerator接口,他们配置了实现类的name为imagecodegenerator,就用他们自己的实现,这样就做到了程序的可扩展性。

Spring Security 图片验证码功能的实例代码

 主要代码:

代码生成器接口validatecodegenerator:

package com.imooc.security.core.validate.code;
import org.springframework.web.context.request.servletwebrequest;
/**
 * 验证码生成接口
 * classname: validatecodegenerator 
 * @description: todo
 * @author lihaoyang
 * @date 2018年3月2日
 */
public interface validatecodegenerator {

 /**
 * 图片验证码生成接口
 * @description: todo
 * @param @param request
 * @param @return 
 * @return imagecode 
 * @throws
 * @author lihaoyang
 * @date 2018年3月2日
 */
 imagecode generator(servletwebrequest request);
}

图片验证码生成器实现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;
/**
 * 图片验证码生成类
 * 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里读取有没有长、宽、字符个数参数,有的话就用,没有用默认的
 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;
/**
 * 配置验证码生成接口validatecodegenerator的实际实现类的bean
 * classname: validatecodebeanconfig 
 * @description: 
 * 配置验证码生成接口validatecodegenerator的实际实现类的bean
 * 如图片验证码的实现、短信验证码的实现
 * @author lihaoyang
 * @date 2018年3月5日
 */
@configuration
public class validatecodebeanconfig {
 @autowired
 private securityproperties securityproperties;
 /**
 * @description: 
 * @conditionalonmissingbean注解意思是当spring容器不存在imagecodegenerator时才给配置一个该bean
 * 作用是使程序更具可扩展性,该配置类是配置在core模块,这就意味着,如果引用该模块的项目
 * 如果有一个自己的实现,实现了validatecodegenerator接口,定义了自己的实现,名字也叫imagecodegenerator时,
 * 就用应用级别的实现,没有的话就用这个默认实现。
 * @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;
 }
}

这样,如果哪个模块引用了这个验证码模块,他自定义了实现,如:

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项目实现的生成验证码,,,");
 return null;
 }
}

这样validatecodebeanconfig在配置验证码bean时,就会使用使用者自定义的实现。

完整代码放在了github:

总结

以上所述是小编给大家介绍的spring security 图片验证码功能的实例代码,希望对大家有所帮助