课程项目设计--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 存放的是外接设备,例如磁盘,光盘等。在其中的外接设备是不能直接被使用的&…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...