【SpringBoot】之Security进阶使用

  🎉🎉欢迎来到我的CSDN主页!🎉🎉

🏅我是君易--鑨,一个在CSDN分享笔记的博主。📚📚

🌟推荐给大家我的博客专栏《SpringBoot开发之Security系列》。🎯🎯

🎁如果感觉还不错的话请给我关注加三连吧!🎁🎁


前言

        上一期的博客中我们一起了解了什么是Security,以及在SpringBoot中集成Security使用,以及一些的基础用法和一些案例演示。今天的这期博客基于上期博客进一步完善使用,请仔细阅读。

一、Security联合数据库使用(登陆功能)

1. 创建所需表

        在我们的数据库中国创建好我们所需要的表,有用户信息表、角色信息表、模块信息表(权限信息表)、用户角色表、角色模块表这五张表。用于后续的权限设置

表名说明
sys_user用户信息表
sys_role角色信息表
sys_module模块信息表(权限信息表)
sys_user_role用户角色表
sys_role_module角色模块表

 表之间的关系说明

         我们可以对用户信息表中的字段进行修改,只保留关键字段,也可以不修改。(我这里只保留了四个字段)

2. 配置文件 

         当然我们要连接数据库需要我们进行导入Mybatis-Plus的依赖以及数据库的依赖。

        当然还需要我们的生成器等等一些配置类 

 MySQLGenerator.java

package com.yx.security.config;import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import lombok.extern.slf4j.Slf4j;import java.util.Arrays;
import java.util.Collections;
import java.util.List;@Slf4j
public class MySQLGenerator {private final static String URL = "jdbc:mysql://localhost:3306/bookshop";private final static String USERNAME = "root";private final static String PASSWORD = "root123";private final static DataSourceConfig.Builder DATA_SOURCE_CONFIG =new DataSourceConfig.Builder(URL, USERNAME, PASSWORD);public static void main(String[] args) {FastAutoGenerator.create(DATA_SOURCE_CONFIG).globalConfig((scanner, builder) ->builder.author(scanner.apply("请输入作者名称?")).outputDir(System.getProperty("user.dir") + "\\src\\main\\java").commentDate("yyyy-MM-dd").dateType(DateType.TIME_PACK).enableSwagger()).packageConfig((builder) ->builder.parent("com.zking.security").entity("pojo").service("service").serviceImpl("service.impl").mapper("mapper").xml("mapper.xml").pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "\\src\\main\\resources\\mapper"))).injectionConfig((builder) ->builder.beforeOutputFile((a, b) -> log.warn("tableInfo: " + a.getEntityName()))).strategyConfig((scanner, builder) ->builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all"))).addTablePrefix("tb_", "t_", "lay_", "meeting_", "sys_", "t_medical_").entityBuilder().enableChainModel().enableLombok().enableTableFieldAnnotation().controllerBuilder().enableRestStyle().enableHyphenStyle().build()).templateEngine(new FreemarkerTemplateEngine()).execute();}protected static List<String> getTables(String tables) {return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));}}

        别忘记了根据项目信息进行修改 

 yml文件配置

server:port: 8080
spring:freemarker:# 设置freemarker模板后缀suffix: .ftl# 设置freemarker模板前缀template-loader-path: classpath:/templates/enabled: truedatasource:driver-class-name: com.mysql.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://localhost:3306/bookshop

生成对应的表

        我们这就只生成用户信息表。

 

        mapper记得打对应的注解,以及在项目启动类中加上扫描mapper的注解

3. 代码编写修改

  IndexController.java
package com.yx.security.controller;import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class IndexController {@RequestMapping("/")public String toLogin(){return "login";}@RequestMapping("/index")public String toIndex(){return "index";}}
index.flt
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title></title>
</head>
<body>
<h1>用户登录</h1>
<form action="/userLogin" method="post"><p><label>用户:<input type="text" name="username"/></label></p><p><label>密码:<input type="password" name="password"/></label></p><input type="submit" value="登录"/><p>${msg!""}</p>
</form>
</body>
</html>

        首先在实体类中实现一个接口——UserDetails类,实现之后会进行一个重新编写四个方法。 

         但是重写方法是返回的值是死的,应该是重数据库中获取的返回值,因此改为定义四个属性及添加指定字段到表中。

         数据库表中的字段注意数驼峰命名用下滑线隔开,默认值都是1.,authorities不是数据库中的字段是代表权限的,待会在类上会打上注释说明,字段会打上注释说明是数据库上的那些字段。

        接下来就是实现功能的代码编写了,首先在实体接口实现类实现UserDetailsService,并且重新方法。

         对其配置类进行修改调整

         直接运行项目进行登陆

 演示

二、密码加密方式

1. 明文不加密

         如果存在多个密码加密方法,并都注释了@Bean注解,则可以用@Primary注解标记使用那个方法。

 2. 自定义MD5加密

        创建自定义MD5加密类并实现PasswordEncoder

PasswordEncoder.java

public class CustomMd5PasswordEncoder implements PasswordEncoder {@Overridepublic String encode(CharSequence rawPassword) {//对密码进行 md5 加密String md5Password = DigestUtils.md5DigestAsHex(rawPassword.toString().getBytes());System.out.println(md5Password);return md5Password;}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {// 通过md5校验System.out.println(rawPassword);System.out.println(encodedPassword);return encode(rawPassword).equals(encodedPassword);}
}

         修改SecurityConfig配置类,更换密码编码器

@Bean
public PasswordEncoder passwordEncoder(){// 自定义MD5加密方式:return new CustomMd5PasswordEncoder();
}

3. BCryptPasswordEncoder密码编码器

        BCryptPasswordEncoderSpring Security中一种基于bcrypt算法的密码加密方式。bcrypt算法是一种密码哈希函数,具有防止彩虹表攻击的优点,因此安全性较高。

        使用BCryptPasswordEncoder进行密码加密时,可以指定一个随机生成的salt值,将其与原始密码一起进行哈希计算。salt值可以增加密码的安全性,因为即使两个用户使用相同的密码,由于使用不同的salt值进行哈希计算,得到的哈希值也是不同的。

        在Spring Security中,可以通过在SecurityConfig配置类中添加以下代码来使用BCryptPasswordEncoder进行密码加密:

@Bean
public PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();
}

三、记住我功能实现(RememberMe )

        在实际开发中,为了用户登录方便常常会启用记住我(Remember-Me)功能。如果用户登录时勾选了“记住我”选项,那么在一段有效时间内,会默认自动登录,免去再次输入用户名、密码等登录操作。该功能的实现机理是根据用户登录信息生成 Token 并保存在用户浏览器的 Cookie 中,当用户需要再次登录时,自动实现校验并建立登录态的一种机制。

Spring Security提供了两种 Remember-Me 的实现方式:

  • 简单加密 Token:用散列算法加密用户必要的登录系信息并生成 Token 令牌。

  • 持久化 Token:数据库等持久性数据存储机制用的持久化 Token 令牌。

1. 创建一张数据表存储信息

  • 创建数据库表 persistent_logins,用于存储自动登录信息

CREATE TABLE `persistent_logins` (`username` varchar(64) NOT NULL,`series` varchar(64) PRIMARY KEY,`token` varchar(64) NOT NULL,`last_used` timestamp NOT NULL
);

2. 修改SecurityConfig配置类

        Remember-Me 功能的开启需要在configure(HttpSecurity http)方法中通过http.rememberMe()配置,该配置主要会在过滤器链中添加 RememberMeAuthenticationFilter 过滤器,通过该过滤器实现自动登录。

        在配置类中添加一个方法

/*** 配置持久化Token方式,注意tokenRepository.setCreateTableOnStartup()配置*/@Beanpublic PersistentTokenRepository persistentTokenRepository(){JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();tokenRepository.setDataSource(dataSource);// 设置为true要保障数据库该表不存在,不然会报异常哦// 所以第二次打开服务器应用程序的时候得把它设为falsetokenRepository.setCreateTableOnStartup(false);return tokenRepository;}

         没创建表的可以将setCreateTableOmStartup的属性值该为true运行时会自动创建。

3. 前端添加组件

    <input type="checkbox" name="remember-me"/>记住我<br/>

4. 配置配置类获取组件

 .rememberMe()// 指定 rememberMe 的参数名,用于在表单中携带 rememberMe 的值。//.rememberMeParameter("remember-me")// 指定 rememberMe 的有效期,单位为秒,默认2周。.tokenValiditySeconds(30)// 指定 rememberMe 的 cookie 名称。.rememberMeCookieName("remember-me-cookie")// 指定 rememberMe 的 token 存储方式,可以使用默认的 PersistentTokenRepository 或自定义的实现。.tokenRepository(persistentTokenRepository())// 指定 rememberMe 的认证方式,需要实现 UserDetailsService 接口,并在其中查询用户信息。.userDetailsService(userDetailsService)

演示效果

        当我们删除网页重新访问主页时会直接进入不会需要登陆 ,数据库中也会生成对应数据,以及网页会生成Cookie

        当我们删除数据库表中的登陆信息数据时,重新刷新主页则访问不了 

四、CSRF防御

        CSRFCross-Site Request Forgery,跨站请求伪造)是一种利用用户已登录的身份在用户不知情的情况下发送恶意请求的攻击方式。攻击者可以通过构造恶意链接或者伪造表单提交等方式,让用户在不知情的情况下执行某些操作,例如修改密码、转账、发表评论等。

为了防范CSRF攻击,常见的做法是在请求中添加一个CSRF Token(也叫做同步令牌、防伪标志),并在服务器端进行验证。CSRF Token是一个随机生成的字符串,每次请求都会随着请求一起发送到服务器端,服务器端会对这个Token进行验证,如果Token不正确,则拒绝执行请求。

1.页面代码加入_csrf隐藏域

 <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

       不添加默认开启了防止跨域攻击的功能,任何 POST 提交到后台的表单都要验证是否带有 _csrf 参数,一旦传来的 _csrf 参数不正确,服务器便返回 403 错误。

如果针对一些特定的请求接口,不需要进行CSRF防御,可以通过以下配置忽略:

http.csrf().ignoringAntMatchers("/upload"); // 禁用/upload接口的CSRF防御

2. SpringSecurity中如何使用CSRF

        在Spring Security中,防范CSRF攻击可以通过启用CSRF保护来实现。启用CSRF保护后,Spring Security会自动在每个表单中添加一个隐藏的CSRF Token字段,并在服务器端进行验证。如果Token验证失败,则会抛出异常,从而拒绝执行请求。启用CSRF保护的方式是在Spring Security配置文件中添加.csrf()方法,例如:

  http.csrf().disable();是禁用CSRF

3. 测试

         我们复制一份登陆表单不携带csrf隐藏域进行测试

        由上图所知,第一个登陆添加了csrf隐藏域能够成功访问主页,第二个登陆没有添加则无法访问。


.csrf()主要方法介绍:
方法说明
disable()关闭CSRF防御
csrfTokenRepository()设置CookieCsrfTokenRepository实例,用于存储和检索CSRF令牌。与HttpSessionCsrfTokenRepository不同,CookieCsrfTokenRepositoryCSRF令牌存储在cookie中,而不是在会话中。
ignoringAntMatchers()设置一组Ant模式,用于忽略某些请求的CSRF保护。例如,如果您想要忽略所有以/api/开头的请求,可以使用.ignoringAntMatchers("/api/**")
csrfTokenManager()设置CsrfTokenManager实例,用于管理CSRF令牌的生成和验证。默认情况下,Spring Security使用DefaultCsrfTokenManager实例来生成和验证CSRF令牌。
requireCsrfProtectionMatcher()设置RequestMatcher实例,用于确定哪些请求需要进行CSRF保护。默认情况下,Spring Security将对所有非GET、HEAD、OPTIONS和TRACE请求进行CSRF保护。

🎉🎉本期的博客分享到此结束🎉🎉

📚📚各位老铁慢慢消化📚📚

🎯🎯下期博客博主会带来新货🎯🎯

🎁三连加关注,阅读不迷路 !🎁

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

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

相关文章

k8s启动docker容器Error: Could not find or load main class ${start-class}报错

前行提要&#xff1a; 今天部署采集点服务&#xff08;docker项目&#xff09;发现报这个错误。 提出假设&#xff1a; 1&#xff0c;配置文件错误&#xff08;工程需要配置的东西比较多&#xff09; 之后开始一一排查&#xff0c;发现配置有问题&#xff0c;但是不是这个错误…

modbus_tcp的实现 through python.

0.引言 当前科技似乎处于加速发展期&#xff0c;各个模块都在快速迭代&#xff0c;迭代的速度会让既有的一些经验产生问题&#xff0c;在用python实现modbus_tcp协议时&#xff0c;网上流传的一些代码中import语句会出现问题。导致pymodbus模块用起来很不好用。 这个原因出在…

【ps】常见工具说明

1&#xff1a;污点修复工具 》内容识别 去除脸部珍珠 》创建纹理 2&#xff1a;修复画笔工具 按住ALT选择一处你想移动的地方 3&#xff1a;修补工具 》内容识别 选择一个区域 将区域内的东西移动到 另一处皮肤上

C语言之字符串

目录 字符串字面量 ​编辑 字符串字面量的长度 ◆具有静态生命周期 ◆对于同一个字符串字面量的处理方式依赖于编译器 字符串 字符数组的初始化赋值 空字符串 字符串的读取 在前面的学习中就会发现&#xff0c;仅仅能用一个字符表示的事物少之又少&#xff0c;对于地…

日志服务 SLS 深度解析:拥抱云原生和 AI,基于 SLS 的可观测分析创新

云布道师 10 月 31 日&#xff0c;杭州云栖大会上&#xff0c;日志服务 SLS 研发负责人简志和产品经理孟威等人发表了《日志服务 SLS 深度解析&#xff1a;拥抱云原生和 AI&#xff0c;基于 SLS 的可观测分析创新》的主题演讲&#xff0c;对阿里云日志服务 SLS 产品服务创新以…

2023/12/21作业

思维导图 代码 .text .global _start _start: 灯1 gpio时钟使能 [4]->1 0x5000A28 LDR R0,0x50000A28 指定寄存器地址 LDR R1,[R0]将寄存器取出放到R1 ORR R1,R1,#(0x1<<4)将第四位设置为1 STR R1,[R0]读取R0寄存器到R1 PE…

Ubuntu 常用命令之 reboot 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 reboot命令在Ubuntu系统中用于重新启动系统。这个命令通常需要管理员权限才能执行。 reboot命令的参数如下 -f 或 --force&#xff1a;强制重启&#xff0c;不调用shutdown -r进行友好重启。-p 或 --poweroff&#xff1a;在重启…

arm和x86架构服务器拉取arm64架构的docker镜像

dockerhub提供的镜像部分支持arm64架构 Docker arm架构服务器拉取docker镜像&#xff0c;默认是arm架构 # docker pull centos Using default tag: latest latest: Pulling from library/centos 52f9ef134af7: Pull complete Digest: sha256:a27fd8080b517143cbbbab9dfb7c8…

HarmonyOS布局之scroll

对于Scroll 布局官方讲解非常好&#xff0c;我在这做个总结&#xff0c;主要结合实际应用进行补充 Scroll — 首先他是一个容器布局&#xff0c;所有的容器布局都可包含子布局&#xff0c;因此scroll 布局也可包含子组件但是&#xff08;他只能包含一个子组件&#xff09;&…

nodejs微信小程序+python+PHP医院挂号系统-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

0基础学习VR全景平台篇第130篇:曝光三要素—感光度

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 众所周知&#xff0c;摄影是一门用光的艺术。随着天气、地点、时间的变化&#xff0c;我们所处环境的光线也随之发生改变。而在不同的环境下该如何去正确的调节曝光&#xff0c;是…

PyTorch加载数据以及Tensorboard的使用

一、PyTorch加载数据初认识 Dataset:提供一种方式去获取数据及其label 如何获取每一个数据及其label 总共有多少的数据 Dataloader:为后面的网络提供不同的数据形式 数据集 在编译器中导入Dataset from torch.utils.data import Dataset 可以在jupyter中查看Dataset官方文档&…

confluence操作手册

文章目录 快捷键插入宏插入代码块 自动为标题编号使用方法&#xff1a; 移动页面到其它目录层级下 快捷键 插入宏 英文输入法下输入{ 插入代码块 输入三个会跳出 点编辑可以调整样式 自动为标题编号 安装插件Numbered Headings 下载链接&#xff1a;https://appfire.…

微服务 Spring Cloud 10,如何追踪微服务调用?服务治理的常见手段

目录 一、服务追踪的作用1、优化系统瓶颈2、优化链路调用3、故障排查4、性能优化5、生成网络拓扑图4、透明传输数据 二、节点管理1、服务调用失败一般有两类原因造成&#xff1a;2、服务调用失败的解决方式&#xff1a;3、服务调用失败的具体解决方式&#xff1a; 三、负载均衡…

ansible的控制语句

本章内容主要介绍 playbook 中的控制语句 使用when判断语句block-rescue判断循环语句 一个play中可以包含多个task&#xff0c;如果不想所有的task全部执行&#xff0c;可以设置只有满足某个条件才执行这个task&#xff0c;不满足条件则不执行此task。本章主要讲解when 和 blo…

Epson爱普生手臂机器人与PC通讯 C#

一、Epson手臂配置 1.安装Epson手臂控制软件 安装Epson手臂控制软体EPSON RC+ 7.0(根据实际需求下载应用),可以去官网下载安装。 2.硬件配置 准备一台PC,用网线连接PC和EPSON手臂控制器。 3.在PC上修改IP地址 EPSON手臂默认IP(192.168.0.1),PC IP改为手臂同一网段…

XML简介 (EXtensible Markup Language)

XML简介 (EXtensible Markup Language) 可扩展标记语言 特点 XML与操作系统、编程语言的开发平台无关实现不同系统之间的数据交换 作用 数据交互配置应用程序和网站Ajax基石 XML标签 XML文档内容由一系列标签元素组成 <元素名 属性名"属性值">元素内容&l…

【模式识别】探秘判别奥秘:Fisher线性判别算法的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《模式之谜 | 数据奇迹解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1f30c;1 初识模式识…

如何通过蓝牙串口启动智能物联网?

1、低功耗蓝牙(BLE)介绍 BLE 技术是一种低成本、短距离、可互操作的鲁棒性无线技术&#xff0c;工作在免许可的 2,4 GHZ 工业、科学、医学(Industrial Scientific Medical&#xff0c;ISM)频段。BLE在设计之初便被定位为一种超低功耗(Ultra Low Power&#xff0c;ULP)无线技术&…

C语言实现UCS2、UTF8与GBK2312编码转换

一、引言 在软件开发中&#xff0c;字符编码是一个非常重要的概念。不同的编码方式用于在不同的系统和应用中表示文本数据。UCS2、UTF8和GBK2312是三种常见的字符编码方式。为了实现不同编码间的转换&#xff0c;我们可以使用C语言进行编程&#xff0c;利用已有的库或者手动实…