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

SpringSecurity实现图形验证码功能实例代码

程序员文章站 2024-02-28 14:22:10
spring security spring security是一个能够为基于spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在sp...

spring security

spring security是一个能够为基于spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在spring应用上下文中配置的bean,充分利用了spring ioc,di(控制反转inversion of control ,di:dependency injection 依赖注入)和aop(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

本文重点给大家介绍springsecurity实现图形验证码功能,具体内容如下:

1.开发生成图形验证码接口

-> 封装imagecode对象,来存放图片验证码的内容、图片以及有效时间

public class imagecode {
 private bufferedimage image;// 图片
 private string code;// 验证码
 private localdatetime expiretime;// 有效时间
 public imagecode(bufferedimage image, string code, int expirein) {
 this.image = image;
 this.code = code;
 // 出入一个秒数,自动转为时间,如过期时间为60s,这里的expirein就是60,转换为当前时间上加上这个秒数
 this.expiretime = localdatetime.now().plusseconds(expirein);
 }
 public imagecode(bufferedimage image, string code, localdatetime expiretime) {
 this.image = image;
 this.code = code;
 this.expiretime = 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;
 }
}

-> 写一个controller用于生成图片和校验验证码

public class validatecodecontroller {
 private static final string session_key = "session_key_image_code";
 private sessionstrategy sessionstrategy = new httpsessionsessionstrategy();
 @getmapping("/code/image")
 public void createcode(httpservletrequest request, httpservletresponse response) throws ioexception {
 // 根据随机数生成图片
 imagecode imagecode = createimagecode(request);
 // 将随机数存到session中
 sessionstrategy.setattribute(new servletwebrequest(request), session_key, imagecode);
 // 将生成的图片写到接口的响应中
 imageio.write(imagecode.getimage(), "jpeg", response.getoutputstream());
 }

 private imagecode createimagecode(httpservletrequest request) {
 // 图片的宽高(像素)
 int width = 67;
 int height = 23;
 // 生成图片对象
 bufferedimage image = new bufferedimage(width, height, bufferedimage.type_int_rgb);
 
 graphics g = image.getgraphics();
 // 生成随机条纹干扰
 random random = new random();
 g.setcolor(getrandcolor(200, 250));
 g.fillrect(0, 0, width, height);
 g.setfont(new font("times new roman", font.italic, 20));
 g.setcolor(getrandcolor(160, 200));
 for (int i = 0; i < 155; i++) {
 int x = random.nextint(width);
 int y = random.nextint(height);
 int xl = random.nextint(12);
 int yl = random.nextint(12);
 g.drawline(x, y, xl, yl);
 }
 
 // 生成四位随机数
 string srand = "";
 for (int i = 0; i < 4; i++) {
 string rand = string.valueof(random.nextint(10));
 srand += rand;
 g.setcolor(new color(20 + random.nextint(110), 20 + random.nextint(110), 20 + random.nextint(110)));
 g.drawstring(rand, 13 * i + 6, 16);
 }
 g.dispose();
 // 60秒有效
 return new imagecode(image, srand, 60);
 }

 /**
 * 生成随机背景条纹
 * @param fc
 * @param bc
 * @return
 */
 private color getrandcolor(int fc, int bc) {
 random random = new random();
 if(fc > 255) {
 fc = 255;
 }
 if(bc > 255) {
 bc = 255;
 }
 int r = fc + random.nextint(bc - fc);
 int g = fc + random.nextint(bc - fc);
 int b = fc + random.nextint(bc - fc);
 return new color(r, g, b);
 }
}

第一步:根据随机数生成图片

imagecode imagecode = createimagecode(request);

第二步:将随机数存到session中

sessionstrategy.setattribute(new servletwebrequest(request), session_key, imagecode);

第三步:将生成的图片写到接口的响应中

imageio.write(imagecode.getimage(), “jpeg”, response.getoutputstream());

-> 在静态页面中加入图片验证码的标签

<tr>
 <td>图形验证码:</td>
 <td>
 <input type="text" name="imagecode">
 <img src="/code/image">
 </td>
</tr>

-> 将接口请求地址配进认证

@override
protected void configure(httpsecurity http) throws exception {
 http.formlogin()
 .loginpage("/authencation/require")
 .loginprocessingurl("/authentication/form")
 .successhandler(imoocauthenticationsuccesshandler)
 .failurehandler(imoocauthenticationfailurehandler)
 .and()
 .authorizerequests()
 .antmatchers("/authencation/require", 
 securitypropertis.getbrowserpropertis().getloginpage(),
 "/code/image").permitall() // 加入"/code/image"地址
 .anyrequest()
 .authenticated()
 .and()
 .csrf().disable();
}

->启动服务器访问静态表单

如图所示:

SpringSecurity实现图形验证码功能实例代码

2.在认证流程中加入图形验证码校验

-> 写一个filter进行拦截
public class validatecodefilter extends onceperrequestfilter{
 private authenticationfailurehandler authenticationfailurehandler;
 private sessionstrategy sessionstrategy = new httpsessionsessionstrategy();
 @override
 protected void dofilterinternal(httpservletrequest request, httpservletresponse response, filterchain filterchain)
 throws servletexception, ioexception {
 //如果访问的是/authentication/form并且为post请求
 if(stringutils.equals("/authentication/form", request.getrequesturi())
 && stringutils.equals(request.getmethod(), "post")) {
 try {
 // 验证图片验证码是否填写正确
 validate(new servletwebrequest(request));
 } catch (validatecodeexception e) {
 // 抛出异常,并返回,不再访问资源
 authenticationfailurehandler.onauthenticationfailure(request, response, e);
 return;
 }
 }
 // 通过,执行后面的filter
 filterchain.dofilter(request, response);
 }
 // 校验验证码的逻辑
 private void validate(servletwebrequest request) throws servletrequestbindingexception {
 imagecode codeinsession = (imagecode) sessionstrategy.getattribute(request, validatecodecontroller.session_key);
 string codeinrequest = servletrequestutils.getstringparameter(request.getrequest(), "imagecode");
 if(stringutils.isblank(codeinrequest)) {
 throw new validatecodeexception("验证码的值不能为空");
 }
 if(codeinsession == null){
 throw new validatecodeexception("验证码不存在");
 }
 if(codeinsession.isexpried()) {
 sessionstrategy.removeattribute(request, validatecodecontroller.session_key);
 throw new validatecodeexception("验证码已过期");
 }
 if(!stringutils.equals(codeinsession.getcode(), codeinrequest)) {
 throw new validatecodeexception("验证码不匹配");
 }
 sessionstrategy.removeattribute(request, validatecodecontroller.session_key);
 }
 public authenticationfailurehandler getauthenticationfailurehandler() {
 return authenticationfailurehandler;
 }
 public void setauthenticationfailurehandler(authenticationfailurehandler authenticationfailurehandler) {
 this.authenticationfailurehandler = authenticationfailurehandler;
 }
 public sessionstrategy getsessionstrategy() {
 return sessionstrategy;
 }
 public void setsessionstrategy(sessionstrategy sessionstrategy) {
 this.sessionstrategy = sessionstrategy;
 }
}

-> 配置再configure中,生效

@override
protected void configure(httpsecurity http) throws exception {
 // 声明filter
 validatecodefilter validatecodefilter = new validatecodefilter();
 // 配置验证失败执行的handler
 validatecodefilter.setauthenticationfailurehandler(imoocauthenticationfailurehandler);
 // 添加filter到认证流程
 http.addfilterbefore(validatecodefilter, usernamepasswordauthenticationfilter.class)
 .formlogin()
 .loginpage("/authencation/require")
 .loginprocessingurl("/authentication/form")
 .successhandler(imoocauthenticationsuccesshandler)
 .failurehandler(imoocauthenticationfailurehandler)
 .and()
 .authorizerequests()
 .antmatchers("/authencation/require", 
 securitypropertis.getbrowserpropertis().getloginpage(),
 "/code/image").permitall()
 .anyrequest()
 .authenticated()
 .and()
 .csrf().disable();
}

至此,图片验证码验证流程已经全部完成。

启动服务,进行测试即可。