课程项目设计--spring security--用户管理功能--宿舍管理系统--springboot后端
还要实习,每次时间好少呀,进度会比较慢一点
本文主要实现是用户管理相关功能。
前文项目建立
文章目录
- 验证码功能
- 验证码配置
- 验证码生成工具类
- 添加依赖
- 功能测试
- 编写controller接口
- 启动项目
- security配置
- 拦截器配置
- 验证码拦截器
- jwt拦截器
- 思考
- 用户登录
- jwt管理
- 验证
- 用户注销
验证码功能
验证码采用的是hutool工具的验证码
hutool官方地址
工具模板采用有来开源组织
验证码配置
yml配置
CaptchaConfig:# 验证码缓存过期时间(单位:秒)ttl: 120l# 验证码内容长度length: 4# 验证码宽度width: 120# 验证码高度height: 40# 验证码字体font-name: Verdana# 验证码字体大小fontSize: 20
配置类
/*** EasyCaptcha 配置类* * @author haoxr* @since 2023/03/24*/
@ConfigurationProperties(prefix = "easy-captcha")
@Configuration
@Data
public class CaptchaConfig {// 验证码类型private CaptchaTypeEnum type = CaptchaTypeEnum.ARITHMETIC;// 验证码缓存过期时间(单位:秒)@Value("${captcha.ttl}")private long ttl;// 内容长度@Value("${captcha.length}")private int length;// 宽度@Value("${captcha.width}")private int width;// 验证码高度@Value("${captcha.height}")private int height;// 验证码字体@Value("${captcha.font-name}")private String fontName;// 字体风格private Integer fontStyle = Font.PLAIN;// 字体大小@Value("${captcha.font-size}")private int fontSize;}
验证码生成工具类
@Component
@RequiredArgsConstructor
public class EasyCaptchaProducer {private final CaptchaConfig captchaConfig;public Captcha getCaptcha() {Captcha captcha;int width = captchaConfig.getWidth();int height = captchaConfig.getHeight();int length = captchaConfig.getLength();String fontName = captchaConfig.getFontName();switch (captchaConfig.getType()) {case ARITHMETIC -> {captcha = new ArithmeticCaptcha(width, height);captcha.setLen(2);}case CHINESE -> {captcha = new ChineseCaptcha(width, height);captcha.setLen(length);}case CHINESE_GIF -> {captcha = new ChineseGifCaptcha(width, height);captcha.setLen(length);}case GIF -> {captcha = new GifCaptcha(width, height);//最后一位是位数captcha.setLen(length);}case SPEC -> {captcha = new SpecCaptcha(width, height);captcha.setLen(length);}default -> throw new RuntimeException("验证码配置信息错误!正确配置查看 CaptchaTypeEnum ");}captcha.setFont(new Font(fontName, captchaConfig.getFontStyle(), captchaConfig.getFontSize()));return captcha;}}
添加依赖
<!-- Java8 之后JavaScript引擎nashorn被移除导致验证码解析报错--><dependency><groupId>org.openjdk.nashorn</groupId><artifactId>nashorn-core</artifactId><version>${nashorn.version}</version></dependency>
功能测试
Captcha captcha = easyCaptchaProducer.getCaptcha();try (OutputStream ops = new FileOutputStream("d://captcha.jpg")) {captcha.out(ops);} catch (Exception e) {e.printStackTrace();}System.out.println(captcha.text());
测试结果


编写controller接口
@Tag(name = "01-认证中心")
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
@Slf4j
public class AuthController {private final EasyCaptchaService easyCaptchaService;@Operation(summary = "获取验证码")@GetMapping("/captcha")public Result<CaptchaResult> getCaptcha() {CaptchaResult captcha = easyCaptchaService.getCaptcha();return Result.success(captcha);}
}
启动项目
记住这里,这是你spring security 的密码

生成http

通过base64转图片的在线工具可以看到

说明编写成功了。
security配置
在上面我们默认的是spring security 自动的密码。我们现在需要自己设置密码。
spring security 框架捏,不太好说这玩意。挺忘记了。
不过spring boot3使用的是spring security6.0版本和以前的有很大差别,6.0通过配置bean来进行。所以也还好,反正都是从头学。
首先需要配置security的配置类
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfig {// 密码编码器@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}/*** 不走过滤器链的放行配置* 默认放行静态资源、登录接口、验证码接口、Swagger接口文档*/@Beanpublic WebSecurityCustomizer webSecurityCustomizer() {return (web) -> web.ignoring().requestMatchers("/auth/captcha","/webjars/**","/doc.html","/swagger-resources/**","/swagger-ui/**","/ws/**");}
}/*** 认证管理器** @param authenticationConfiguration 认证配置* @return 认证管理器* @throws Exception 异常*/@Beanpublic AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {return authenticationConfiguration.getAuthenticationManager();}@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(requestMatcherRegistry ->requestMatcherRegistry.requestMatchers(SecurityConstants.LOGIN_PATH).permitAll().anyRequest().authenticated()).sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).exceptionHandling(httpSecurityExceptionHandlingConfigurer ->httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler)).csrf(AbstractHttpConfigurer::disable);// 验证码校验过滤器http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class);// JWT 校验过滤器http.addFilterBefore(new JwtAuthenticationFilter(jwtTokenManager), UsernamePasswordAuthenticationFilter.class);return http.build();}
这里还用到了2个拦截器
拦截器配置
验证码拦截器
需求:对登录请求进行拦截,如果是登录则需要先校验验证码是否正常,如果正确则放行。其他请求则直接放行。
public class VerifyCodeFilter extends OncePerRequestFilter {private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(SecurityConstants.LOGIN_PATH, "POST");public static final String VERIFY_CODE_PARAM_KEY = "verifyCode";public static final String VERIFY_CODE_KEY_PARAM_KEY = "verifyCodeKey";@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 如果是登录请求则校验验证码if (LOGIN_PATH_REQUEST_MATCHER.matches(request)){String code = request.getParameter(VERIFY_CODE_PARAM_KEY);String verifyCodeKey = request.getParameter(VERIFY_CODE_KEY_PARAM_KEY);// 由于这个不是bean,不能通过注入的方式获取,所以通过SpringUtil工具类获取RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate", RedisTemplate.class);String cacheCode = Convert.toStr(redisTemplate.opsForValue().get(SecurityConstants.VERIFY_CODE_CACHE_PREFIX + verifyCodeKey));if (cacheCode == null) {// 验证码过期ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_TIMEOUT);return;}if (!StrUtil.equals(cacheCode,code)) {// 验证码错误ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_ERROR);return;}}filterChain.doFilter(request, response);}
}
jwt拦截器
需求:处理登录请求以外的请求,每次需要验证jwt令牌,如果没问题则在该线程请求附加权限身份。
public class JwtAuthenticationFilter extends OncePerRequestFilter {private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(SecurityConstants.LOGIN_PATH, "POST");private final JwtTokenManager tokenManager;public JwtAuthenticationFilter(JwtTokenManager jwtTokenManager) {this.tokenManager = jwtTokenManager;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {if (!LOGIN_PATH_REQUEST_MATCHER.matches(request)) {String jwt = RequestUtils.resolveToken(request);if (StringUtils.hasText(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {try {Claims claims = this.tokenManager.parseAndValidateToken(jwt);Authentication authentication = this.tokenManager.getAuthentication(claims);SecurityContextHolder.getContext().setAuthentication(authentication);} catch (Exception e) {ResponseUtils.writeErrMsg(response, ResultCode.TOKEN_INVALID);}} else {ResponseUtils.writeErrMsg(response, ResultCode.TOKEN_INVALID);}}chain.doFilter(request, response);}
}
思考
这2个拦截器一个需要登录一个除去登录,那么是不是可以放到一个拦截器里面去。各走各的。这样也明确一点。也不用2个拦截器找了。
如果改了记得改securityFilterChain
用户登录
需求:输入用户名和密码,验证用户身份。
需要写一个类继承UserDetails

另一个实现类继承SysUserService(SysUserDetailsService)

这2个一个是存储一个是查询。然后会自动和输入的username以及password进行比对
验证流程后面总结一个spring security的文。
SysUserDetailsService作用是查询该用户名的角色信息并返回UserDetails。
查询,调用SysUserService根据用户名查询所有的

由于认证信息需要角色信息和权限所以我们需要联表查询角色信息。
在依据角色信息查询权限。
select u.id userId,u.name username,u.password,u.role,u.avatar,u.email,u.status,r.codefrom sys_user uleft join sys_user_role sur on u.id = sur.user_idleft join sys_role r on sur.role_id = r.idwhere u.name = #{username}AND u.deleted = 0
然后在依据角色查询权限
不过我感觉这个type硬编码挺严重的,也算学习一下这种mybatis里面枚举了。
如果没用角色则m.id = -1让其没权限。
<select id="listRolePerms" resultType="java.lang.String">select distinct m.permfrom sys_menu minner join sys_role_menu rm on m.id = rm.menu_idinner join sys_role r on r.id = rm.role_idwhere m.type = '${@com.yu.common.enums.MenuTypeEnum@BUTTON.getValue()}'and m.perm is not null<choose><when test="roles!=null and roles.size()>0">and r.code in<foreach collection="roles" item="role" open="(" close=")" separator=",">#{role}</foreach></when><otherwise>and m.id = -1</otherwise></choose></select>
controller验证,很明确的流程就是封装输入的,然后进行验证。失败了会报错返回。
成功则生成token将权限放入redis,将角色,用户名,id封装进jwt
然后进行返回。接下来查看jwtTokenManager.createToken
@Operation(summary = "登录")@PostMapping("/login")public Result<LoginResult> login(@Parameter(description = "用户名", example = "admin") @RequestParam String username,@Parameter(description = "密码", example = "123456") @RequestParam String password) {// 存储username和passwordUsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username.toLowerCase().trim(),password);// 验证用户名和密码Authentication authentication = authenticationManager.authenticate(authenticationToken);// 生成tokenString accessToken = jwtTokenManager.createToken(authentication);// 返回tokenLoginResult loginResult = LoginResult.builder().tokenType("Bearer").accessToken(accessToken).build();return Result.success(loginResult);}@Schema(description ="登录响应对象")@Builderpublic static record LoginResult(@Schema(description = "访问token")String accessToken,@Schema(description = "token 类型",example = "Bearer")String tokenType,@Schema(description = "刷新token")String refreshToken,@Schema(description = "过期时间(单位:毫秒)")Long expires) {}
jwt管理
采用hutool工具包进行jwt管理,以前用过java-jwt的,这次试试hutool。
/*** 创建token** @param authentication auth info* @return token*/public String createToken(Authentication authentication) {SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();// 角色放入JWT的claimsSet<String> roles = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());// 权限数据多放入RedisSet<String> perms = userDetails.getPerms();redisTemplate.opsForValue().set(SecurityConstants.USER_PERMS_CACHE_PREFIX + userDetails.getUserId(), perms);Map<String, Object> claims = Map.of(JWTPayload.ISSUED_AT, DateTime.now(),JWTPayload.EXPIRES_AT, DateTime.now().offset(DateField.SECOND, tokenTtl),"jti", IdUtil.fastSimpleUUID(),"userId", userDetails.getUserId(),"username", userDetails.getUsername(),"authorities", roles);return JWTUtil.createToken(claims, getSecretKeyBytes());}
验证
http测试:
之前测试挺头疼的。
需要先发送验证码的。
然后去base64转图片(后面直接打印了结果了)
进行测试

成功

后面去vue3前端测了。用的是有来开源vue3-element-admin修改。
成功了!

用户注销
待续
相关文章:
课程项目设计--spring security--用户管理功能--宿舍管理系统--springboot后端
写在前面: 还要实习,每次时间好少呀,进度会比较慢一点 本文主要实现是用户管理相关功能。 前文项目建立 文章目录 验证码功能验证码配置验证码生成工具类添加依赖功能测试编写controller接口启动项目 security配置拦截器配置验证码拦截器 …...
学习设计模式之装饰器模式,但是宝可梦
装饰模式 为了不改变组件的结构,动态地扩展其功能。 通常,扩展功能通过子类进行,但是继承的方式具有静态特征,耦合度高。 意图:动态地给对象添加额外的功能 主要解决:继承方式是静态特征,扩…...
【AWS】创建IAM用户;无法登录IAM用户怎么办?错误提示:您的身份验证信息错误,请重试(已解决)
目录 0.背景问题分析 1.解决步骤 0.背景问题分析 windows 11 ,64位 我的问题情景: 首先我创建了aws的账户,并且可以用ROOT用户登录,但是在登录时选择IAM用户,输入ROOT的名字和密码,就会提示【您的身份验证…...
微服务基础知识
文章目录 微服务基础知识一、系统架构的演变1、单体应用架构2、垂直应用架构3、分布式SOA架构(1)什么是SOA(2)SOA架构 4、微服务架构5、SOA和微服务的关系(1)SOA(2)微服务架构 二、分…...
倒残差结构
倒残差结构: 倒残差结构是MobileNetV2中引入的一种设计,用于增强网络的表达能力和特征提取能力,同时保持轻量级的特点。它的核心思想是在每个瓶颈块中,先使用一个扩张卷积(Dilated Convolution)&#x…...
Docker的基本使用
Docker 概念 Docker架构 docker分为客户端,Docker服务端,仓库 客户端 Docker 是一个客户端-服务器(C/S)架构程序。Docker 客户端只需要向 Docker 服务端发起请求,服务端将完成所有的工作并返回相应结果。 Docker …...
paddlenlp安装踩坑记录
错误1 ModuleNotFoundError: No module named paddle.metric我下载paddlepaddle-gpu2.5.0.post117解决了,最开始下载的2.5.1报错,post后面的117是我的cuda版本,不要写你对应的版本号 python3 -m pip install paddlepaddle-gpu2.5.0.post117…...
微服务流程引擎:简单又灵活,实现流程全生命周期管理!
伴随着日益激烈的市场竞争,传统的办公操作已经无法满足发展需要了。如果采用微服务流程引擎加油助力,就可以帮助企业更好地管理数据资源,高效做好各种表单制作,实现高效率办公。流辰信息以市场为导向,用心钻研低代码技…...
Qt表格数据处理
概述 在Qt表格数据处理中,涉及到如下几个具体的类: QAbstractItemModel:这是一个抽象基类,定义了模型(Model)的接口规范。所有的模型类都应该派生自QAbstractItemModel,并实现它的纯虚函数&…...
EasyPOI 实战总结
EasyPOI实战总结 简介 easypoi功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板 语言(熟悉的表达式语法),完成以前复杂的写法 使用EasyPOI 环境搭建 # 1.引入相关依…...
【LeetCode-困难题】42. 接雨水
题目 题解一:暴力双重for循环(以行计算水量) 1.先找出最高的柱子有多高(max 3) 2.然后第一个for为行数(1,2,3) 3.第二个for计算每一行的雨水量(关键在于去除…...
npm install 安装依赖,报错 Host key verification failed
设置 git 的身份和邮箱 git config --global user.name "你的名字" > 用户名 git config --global user.email “你的邮箱" > 邮箱进入 > 用户 > [你的用户名] > .ssh文件夹下,删除 known_hosts 文件即可 进入之后有可能会看到 known_hosts…...
SOLIDWORKS焊件是什么?
SOLIDWORKS是一款广泛应用于机械设计领域的三维计算机辅助设计软件。SOLIDWORKS提供了强大的焊件功能,可以帮助工程师们以更高的效率设计焊接件。本文将介绍SOLIDWORKS焊件的概念、特点以及使用方法,以期帮助读者更好地理解和应用这一关键技术。 SOLIDWO…...
2023国赛数学建模D题思路模型代码 高教社杯
本次比赛我们将会全程更新思路模型及代码,大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…...
git协议实现管理(三个步骤)
GitHub官网访问: https://github.com/dashboard 初次使用git的用户要使用git协议大概需要三个步骤: 一、生成密钥对 二、设置远程仓库(本文以github为例)上的公钥 三、把git的remote url远程仓库URL可访问路径修改为git协议(以上两个步骤初次设置过以后,…...
“深入理解JVM:探索Java虚拟机的内部机制“
标题:深入理解JVM:探索Java虚拟机的内部机制 摘要: Java虚拟机(Java Virtual Machine,JVM)是Java语言的核心,负责将Java源代码编译成可执行的字节码并运行。本篇博客将深入探索JVM的内部机制&a…...
Unity——各种特效的基本使用方法
特效是游戏制作不可或缺的一环,作为游戏开发者最重要的工作就是将特效添加到游戏中,并在合适的时机、合适的位置将特效播放出来,同时还要注意特效的管理和销毁。 某些种类的特效,如动效、贴花,还要编写脚本代码以实现…...
smiley-http-proxy-servlet 实现springboot 反向代理,结合项目鉴权,安全的引入第三方项目服务
项目中反向代理 集成第三方的服务接口或web监控界面,并实现与自身项目相结合的鉴权方法 依赖 smiley-http-proxy-servlet GitHub链接 2.0 版开始,代理切换到jakarta servlet-api<!--HTTP 代理 Servlet--><dependency><groupId>org.mit…...
(vue)多级表头且转为百分比显示
(vue)多级表头且转为百分比显示 <el-table-column align"center" label"近三个月数据情况"><el-table-column align"center" prop"amount" :label"tableLast[0]"><template slot-scope"{ row }"&g…...
Linux下C++开发
Linux下C开发 Linux 系统介绍 简介 Linux属于多用户多任务操作系统,而Windows属于单用户多任务操作系统Linux一切皆文件目录结构 bin 存储二进制可执行文件dev 存放的是外接设备,例如磁盘,光盘等。在其中的外接设备是不能直接被使用的&…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
