springsecurity集成kaptcha功能

前端代码

本次采用简单的html静态页面作为演示,也可结合vue前后端分离开发,复制就可运行测试

项目目录

登录界面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script type="text/javascript">function refresh() {document.getElementById('captcha_img').src="/kaptcha?"+Math.random();}</script>
</head>
<body>
<form action="/login" method="post">账号:<input type="text" placeholder="请输入账号" name="username"><br>密码:<input type="password" placeholder="请输入密码" name="password"><br>验证码:  <input type="text" placeholder="请输入验证码" name="code"><div class="item-input"><img id="captcha_img" alt="点击更换" title="点击更换"onclick="refresh()" src="/kaptcha" /></div>记住我:<input type="checkbox" name="remember-me" value="true"><br><input type="submit" value="提交"/>
</form>
</body>
</html>

登录成功

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
成功<a href="/logout">退出</a>
</body>
</html>

后端代码

pom

    <dependencies><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--图形验证码--><dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency><!--security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-test</artifactId><scope>test</scope></dependency><!--数据库--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency></dependencies>

配置类

kaptcha配置类用于生成验证码格式

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Properties;@Configuration
public class KaptchaConfiguration {@Beanpublic DefaultKaptcha getDefaultKaptcha() {com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();Properties properties = new Properties();properties.put("kaptcha.textproducer.char.string", "0123456789");properties.put("kaptcha.border", "no");properties.put("kaptcha.textproducer.font.color", "black");properties.put("kaptcha.textproducer.char.space", "5");properties.put("kaptcha.textproducer.char.length","4");properties.put("kaptcha.image.height","34");properties.put("kaptcha.textproducer.font.size","30");properties.setProperty("kaptcha.image.width", "164");properties.setProperty("kaptcha.image.height", "64");properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");Config config = new Config(properties);defaultKaptcha.setConfig(config);return defaultKaptcha;}}

springsecurity

import com.sfy.kapcha.filter.CodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import javax.sql.DataSource;@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate DataSource dataSource;@AutowiredPersistentTokenRepository persistentTokenRepository;@Beanpublic PasswordEncoder getPw(){return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 基于内存存储的多用户auth.inMemoryAuthentication().withUser("admin").password(getPw().encode("123")).roles("root");}@Overridepublic void configure(WebSecurity web) throws Exception {// 忽略静态请求web.ignoring().antMatchers("/img/**", "/js/**");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.formLogin()//当发现是login时认为是登录,必须和表单提供的地址一致去执行UserDetailsServiceImpl.loginProcessingUrl("/login")//自定义登录界面.loginPage("/login.html").successForwardUrl("/toMain").permitAll().and().addFilterBefore(new CodeFilter(), UsernamePasswordAuthenticationFilter.class);//认证授权http.authorizeRequests().antMatchers("/kaptcha").permitAll()//登录放行不需要认证.antMatchers("/login.html").permitAll()//所有请求都被拦截类似于mvc必须登录后访问.anyRequest().authenticated();//关闭csrf防护http.csrf().disable();//退出登录http.logout().logoutSuccessUrl("/login.html");//记住我http.rememberMe().tokenValiditySeconds(60);}@Beanpublic AuthenticationManager authenticationManagerBean()throws Exception {return super.authenticationManagerBean();}@Beanpublic PersistentTokenRepository getPersistentTokenRepository(){JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();jdbcTokenRepository.setDataSource(dataSource);//第一次启动时建表,第二次使用时注释掉//jdbcTokenRepository.setCreateTableOnStartup(true);return jdbcTokenRepository;}
}

controller

kaptcha

import com.google.code.kaptcha.Constants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;/*** @Author: sfy* @Date: 2024/1/18 11:13*/@RestController
public class KapchaController {@AutowiredDefaultKaptcha defaultKaptcha;@GetMapping("/kaptcha")public void getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpSession session = request.getSession();response.setDateHeader("Expires", 0);response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");response.addHeader("Cache-Control", "post-check=0, pre-check=0");response.setHeader("Pragma", "no-cache");response.setContentType("image/jpeg");// 创建验证码String capText = defaultKaptcha.createText();// 验证码放入sessionsession.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);BufferedImage bi = defaultKaptcha.createImage(capText);ServletOutputStream out = response.getOutputStream();ImageIO.write(bi, "jpg", out);try {out.flush();} finally {out.close();}}}

 login进行简单的页面重定向(要用Controller)

@Controller
public class LoginController {@RequestMapping("/toMain")public String toMain(){return "redirect:main.html";}}

filter

用于检测图像验证码的正确性,只有当验证码正确时,过滤器链才会走到springsecurity的检测

public class CodeFilter extends HttpFilter {@Overrideprotected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {String uri = req.getServletPath();if (uri.equals("/login") && req.getMethod().equalsIgnoreCase("post")) {// 服务端生成的验证码数据String sessionCode = req.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY).toString();System.out.println("正确的验证码: " + sessionCode);// 用户输入的验证码数据String formCode = req.getParameter("code").trim();System.out.println("用户输入的验证码: " + formCode);if (StringUtils.isEmpty(formCode)) {throw new RuntimeException("验证码不能为空");}if (sessionCode.equals(formCode)) {System.out.println("验证通过");} else {throw new AuthenticationServiceException("验证码输入不正确");}}chain.doFilter(req, res);}}

 数据库

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/security?serverTimezone=GMT%2B8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rootmain:allow-circular-references: true #开始支持spring循环依赖

当第一次执行项目时,会在库中生成表数据 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/639920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式-9】装饰模式的代码实现及使用场景

装饰器模式类比生活中房屋装修的场景&#xff0c;可以在毛坯房的基础上加以各种装饰&#xff0c;使得房屋的居住属性增强。装饰器模式能够在运行期间&#xff0c;动态地为原始对象增加一些额外的功能&#xff0c;使其功能更为丰富。 1. 概述 装饰模式 可以动态的为某些对象增…

深入Matplotlib:画布分区与高级图形展示【第33篇—python:Matplotlib】

文章目录 Matplotlib画布分区技术详解引言方法一&#xff1a;plt.subplot()方法二&#xff1a;简略写法方法三&#xff1a;plt.subplots()实例展示添加更多元素 进一步探索Matplotlib画布分区自定义子图布局3D子图结语 Matplotlib画布分区技术详解 引言 Matplotlib是一个强大…

代码随想录27期|Python|Day35|435. 无重叠区间|763.划分字母区间|56. 合并区间

435. 无重叠区间 和昨天的射爆气球是一样的处理方式&#xff1a; 由于不需要进行不重合的时候的计算&#xff0c;只需要对重合进行处理&#xff0c;所以反而更加简单。 1、按照区间左边界从小到大排序&#xff1b; 2、从索引1开始遍历&#xff0c;对于i-1的右边界大于i的左边…

网页无法访问但是有网什么原因

目录 1.运行网络诊断&#xff0c;确认原因 原因A.远程计算机或设备将不接受连接(该设备或资源(Web 代理)未设置为接受端口“7890”上的连接 原因B.DNS服务器未响应 场景A.其他的浏览器可以打开网页&#xff0c;自带的Edge却不行 方法A&#xff1a;关闭代理 Google自带翻译…

用户头像上传

将用户上传的头像存储在腾讯云存储桶里 注册腾讯云 https://cloud.tencent.com/login 创建存储桶 配置跨域 来源 * (任何都可以访问) put get post 请求都可以 点击概览&#xff0c;查看存储桶基本信息 记录保存存储桶名称和地域 找到api密钥管理&#xff0c;新建密钥 ht…

配置git环境

目录 一、安装[Git Bash](https://gitforwindows.org/)二、进入家目录生成秘钥&#xff1a;执行命令ssh-keygen三、在[Ac Git](https://git.acwing.com/)上注册账号四、将id_rsa.pub的内容复制到Ac Git上Reference 一、安装Git Bash 二、进入家目录生成秘钥&#xff1a;执行命…

Mongodb 控制查询返回字段

使用关系型数据库时&#xff0c;用户在select命令后添加字段名称控制返回字段。mongodb中也支持对查询返回字段的控制。默认返回文档的所有字段。为了限制返回数据量&#xff0c;提高网络传输速率。用户可以通过投射&#xff08;projection&#xff09;来指定返回字段或在返回结…

Git学习笔记(第7章):IDEA实现Git操作(VSCode)

目录 7.1 配置忽略文件 7.2 初始化本地库 7.3 添加暂存区、提交本地库 7.4 修改文件 补充&#xff1a;工具栏简介 7.1 配置忽略文件 问题引入 在版本控制系统中&#xff0c;有些文件或目录是不需要纳入版本管理的&#xff0c;比如编译产生的临时文件、日志文件、缓存文件等…

项目篇:基于UDP通信模型的网络聊天室

思维导图 基于UDP通信模型的网络聊天室 消息分类及数据包结构 服务器端 #include <head.h> #define SER_PORT 8888 #define SER_IP "192.168.232.133" typedef struct mb {struct sockaddr_in cin;char name[20];struct mb *next; }*member; //群发消息 int …

计算机网络复试

第1章 概述 时延&#xff1a;发送(传输)时延传播时延 链路中每多一个路由器&#xff0c;就增加一个分组的发送时延 第2章 物理层 2.4 编码与调制->编码(基带调制)->曼彻斯特编码 ->带通调制->混合调制->正交振幅调制QAM 信道极限容量 奈氏准则 无噪声最大速…

【window】Windows11:该文件没有与之关联的应用来执行该操作

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff1a;人工智能 之前win10升级win11后&#xff0c;受不了桌面软件图标的的小箭头&#xff0c;所以弄掉了&#xff0c;但是随之而来产…

Linux修改文件名常见的三种方式

在Linux系统中&#xff0c;有多种方式可以修改文件名。以下是其中的三种常见方式&#xff1a; 1. List item 使用mv命令&#xff1a; mv oldfilename newfilename例如&#xff0c;要将文件"oldfile.txt"重命名为"newfile.txt"&#xff0c;可以使用以下命…

9个好习惯教会你设计商业模式的电商干货,真心分享丨运营逻辑

9个好习惯教会你设计商业模式的电商干货&#xff0c;真心分享丨运营逻辑 文丨微三云营销总监胡佳东&#xff0c;点击上方“关注”&#xff0c;为你分享市场商业模式电商干货。 - 最近&#xff0c;有很多新认识的朋友&#xff0c;都在询问我最近市场上&#xff0c;有什么好的…

定类变量的频率分析(SPSS

目录 1.导入数据&#xff1a;2.频率分析&#xff1a;3.结果分析4.表格导出为excel小结&#xff1a; 1.导入数据&#xff1a; 直接把表格拖入spss 然后点确定 下面会有变量视图&#xff0c;查看各个指标的类型和属性&#xff1a; 2.频率分析&#xff1a; 点击频率分析 选择…

json-server的基础使用

本篇文章与另一篇文章有关系axios的基本使用&#xff0c;大家可以看看这篇文章 json-server 是什么? 用来快速搭建模拟的 REST API 的工具包 可以30秒内快速为我们搭建一个假的基于 REST API的服务 我们要如何使用呢&#xff1f; 1.先安装 //全局安装 npm i -g json-server …

伪原创文章生成器软件免费使用的方法

写文章不仅消耗时间&#xff0c;而且还容易出现写不出内容的问题&#xff0c;随着技术的发展&#xff0c;越来越多的人开始不再亲历亲为的去写文章了&#xff0c;而是用起了伪原创文章生成器软件&#xff0c;对于还不了解自动生成文章软件的人&#xff0c;可不要小瞧这个它了&a…

JOSEF约瑟 零序电流继电器 JL-8D/2X122A4(S) 0-30AAC 220VDC

系列型号 JL-8D/3X1定时限电流继电器&#xff1b;JL-8D/3X111A2定时限电流继电器&#xff1b; JL-8D/3X121A2定时限电流继电器&#xff1b;JL-8D/3X211A2定时限电流继电器&#xff1b; JL-8D/3X221A2定时限电流继电器&#xff1b;JL-8D/3X2定时限电流继电器&#xff1b; JL-8D/…

[小程序]Http网络请求

一、数据请求限制 出于安全性(bushi)考虑&#xff0c;小程序请求的数据接口必须具备以下两个条件&#xff1a; ①只能请求Https类型 ②必须将接口域名添加到信任列表中 1.配置request合法域名 配置步骤如下&#xff1a;小程序管理后台->开发->开发设置->服务器域名-&g…

golang any 之中的类型及 interface 接口

在 golang 之中 any 类型&#xff0c;从字面意思上看是任意类型&#xff0c;这很类似我们在 C#、C 之中的任意指针类型 void*&#xff08;原生&#xff09;&#xff0c;C# 之中诡异的 object。 any 是一个接口类型&#xff0c;其语法声明为&#xff1a; // any is an alias fo…

JavaScript 基础语法

文章目录 逻辑控制语句直接从页面输出数据类型相加循环语句测试语法 逻辑控制语句 function print(){//注意常量尽量全部使用大写const SEASON 3 if(SEASON>1&&SEASON<3){console.log(春天来了)}else if(SEASON>4&&SEASON<6){console.log(夏天来…