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.hqwc.cn/news/422769.html

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

相关文章

【.NET Core】多线程之线程池(ThreadPool)详解(一)

【.NET Core】多线程之线程池&#xff08;ThreadPool&#xff09;详解&#xff08;一&#xff09; 文章目录 【.NET Core】多线程之线程池&#xff08;ThreadPool&#xff09;详解&#xff08;一&#xff09;一、概述二、线程池的应用范围三、线程池特性3.1 线程池线程中的异常…

OR36 链表的回文结构

目录 一、思路 二、代码 一、思路 找到中间节点 后半部分逆置链表 定义两个指针&#xff0c;一个从头开始出发 一个从中间位置开始出发 但是注意&#xff1a;链表个数可能是奇数或者偶数&#xff0c;需要注意中间节点的计算 二、代码 struct ListNode* reverseList(str…

linux的kali安装,换源,更新包

下载kali kali.org进入官网后点第二个 然后点第一个 解压kali 下载后获得.7z压缩包&#xff0c;建议移动到合适自己电脑的位置进行解压&#xff0c;我喜欢放在D盘 启动kali 双击进入解压出的文件夹&#xff0c;将唯一一个.vmx文件用vmware打开&#xff08;没装的自行提前装…

【Redis】更改redis中的value值

今天继续进步一点点~~ 背景&#xff1a;今天有个前端的同事问我&#xff0c;能不能在Redis中他本人登录公众号的 sessionID 加上一列openID 于是我上网查了一堆在Redis里面的命令&#xff0c;以及不同的客户端怎么输入命令&#xff0c;但是后来问了下同事&#xff0c;他就给我…

[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…

设置代码模板创建sql映射文件、Mybatis主配置文件

目录 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 2、Mybatis的主配置文件的介绍 3、通过代码模板创建Sql映射文件 4、通过代码模板创建Mybatis主配置文件 1、Sql映射&#xff08;Sql Mapper&#xff09;文件的介绍 <?xml version"1.0" encod…

国产操作系统:VirtualBox安装openKylin-1.0.1虚拟机并配置网络

国产操作系统&#xff1a;VirtualBox安装openKylin-1.0.1虚拟机并配置网络 openKylin 操作系统目前适配支持X86、ARM、RISC-V三个架构的个人电脑、平板电脑及教育开发板&#xff0c;可以满足绝大多数个人用户及开发者的使用需求。适用于在VirtualBox平台上安装openKylin-1.0.1…

梳理一下若依框架的权限过滤系统

梳理一下若依框架的权限过滤系统 首先&#xff0c;我们直入主题&#xff0c;且看这段代码 /*** 获取用户列表*/ PreAuthorize("ss.hasPermi(system:user:list)") GetMapping("/list") public TableDataInfo list(SysUser user) {startPage();List<SysU…

力扣62. 不同路径

动态规划 思路&#xff1a; 定义 dp[r][c] 为到达坐标 (r, c) 的路径数&#xff1a; 它只能有同一行左边相邻方格向右到达或者同一列上方相邻方格向下到达&#xff1b;状态转移方程&#xff1a; dp[r][c] dp[r][c - 1] dp[r - 1][c]初始状态 dp[0][0] 1第一行的路径数是 1第…

GPT-4开启人工智能赋能教育的新时代

2022年11月30日&#xff0c;美国 OpenAI公司发布了一款最新研发的生成式人工智能产品——ChatGPT&#xff08;Chat Generative Pre-trained Transformer&#xff09;。ChatGPT的推出&#xff0c;仅用了短短两个月时间就快速占领了人工智能领域的主导地位&#xff0c;成为历史上…

你必须知道postman和Jmeter做接口测试区别

1. 用例组织方式 Jmeter的组织方式相对比较扁平&#xff0c;它首先没有WorkSpace的概念&#xff0c;直接是TestPlan&#xff0c;TestPlan下创建的Threads Group就相当于TestCase&#xff0c;并没有TestSuite的层级。 Postman功能上更简单&#xff0c;组织方式也更轻量级&…

【代码实战】从0到1实现transformer

获取数据 import pathlibimport tensorflow as tf# download dataset provided by Anki: https://www.manythings.org/anki/ text_file tf.keras.utils.get_file(fname"fra-eng.zip",origin"http://storage.googleapis.com/download.tensorflow.org/data/fra-…