第四阶段-12关于Spring Security框架,RBAC,密码加密原则

news2025/1/17 6:18:13

关于csmall-passport项目

此项目主要用于实现“管理员”账号的后台管理功能,主要实现:

  • 管理员登录
  • 添加管理员
  • 删除管理员
  • 显示管理员列表
  • 启用 / 禁用管理员

关于RBAC

RBAC:Role-Based Access Control,基于角色的访问控制

在涉及权限管理的应用软件设计中,应该至少需要设计以下3张数据表:

  • 用户表
  • 角色表
  • 权限表

并且,还至少需要2张关联表:

  • 用户与角色的关联表
  • 角色与权限的关联表

关于Spring Security框架

Spring Security主要解决了认证与授权相关的问题。

认证:判断某个账号是否允许访问某个系统,简单来说,就是验证登录

授权:判断是否允许已经通过认证的账号访问某个资源,简单来说,就是判断是否具有权限执行某项操作

添加依赖

在基于Spring Boot的项目中,使用Spring Security需要添加依赖项:

<!-- Spring Boot Security依赖项,用于处理认证与授权相关的问题 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

当在项目中添加以上依赖项后,你的项目会发生以下变化(Spring Boot中的Spring Security的默认行为):

  • 所有的请求都是必须要登录才允许访问的,包括错误的URL

  • 提供了默认的登录页面,当未登录时,会自动重定向到此登录页面

  • 提供了临时的登录账号,用户名是user,密码是启动项目时在控制台中的UUID值(每次重启项目都会不同)

请添加图片描述

  • 当登录成功后,将自动重定向到此前尝试访问的URL,如果此前没有尝试访问某个URL,则重定向到根路径
  • 可以通过 /logout 路径访问到“退出登录”的页面,以实现登出
  • 当登录成功后,POST请求都是不允许的,而GET请求是允许的

关于Spring Security的配置类

在项目的根包下,创建config.SecurityConfiguration类,继承自WebSecurityConfigurerAdapter类,在类上添加@Configuration注解:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
}

然后,在类中重写void configure(HttpSecurity http)方法:

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

    }

}

**注意:**在重写的方法中,不要使用super调用父类的此方法!

由于没有调用父类此方法,再次重启项目后,与此前将有些不同:

  • 所有请求都不再要求登录
  • 登录、登出的URL不可访问

关于登录表单

在Spring Security配置类的configure(HttpSecurity http)方法中,根据是否调用了参数对象的formLogin()方法,决定是否启用登录表单页(/login)和登出页(/logout),例如:

@Override
protected void configure(HttpSecurity http) throws Exception {
    // 调用formLogin()表示启用登录表单页和登出页,如果未调用此方法,则没有登录表单页和登出页
    http.formLogin();
}

关于URL的访问控制

在Spring Security配置类的configure(HttpSecurity http)方法中,

// 白名单
// 使用1个星号,表示通配此层级的任意资源,例如:/admin/*,可以匹配 /admin/delete、/admin/add-new
// 但是,不可以匹配多个层级,例如:/admin/*,不可以匹配 /admin/9527/delete
// 使用2个连续的星号,表示通配任何层级的任意资源,例如:/admin/**,可以匹配 /admin/delete、/admin/9527/delete
String[] urls = {
        "/doc.html",
        "/**/*.js",
        "/**/*.css",
        "/swagger-resources",
        "/v2/api-docs"
};

// 配置URL的访问控制
http.authorizeRequests() // 配置URL的访问控制
        .mvcMatchers(urls) // 匹配某些URL
        .permitAll() // 直接许可,即:不需要通过认证就可以直接访问
        .anyRequest() // 任何请求
        .authenticated(); // 以上配置的请求需要是通过认证的

使用临时的自定义账号实现登录

可以自定义类,实现UserDetailsService接口,并保证此类是组件类,则Spring Security框架会基于此实现类来处理认证。

在项目的根包下创建security.UserDetailsServiceImpl类,实现UserDetailsService接口,并在类上添加@Service注解,重写接口中定义的抽象方法:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) 
        						throws UsernameNotFoundException {
        return null;
    }
}

当项目中存在UserDetailsService类型的组件对象时,尝试登录时,Spring Security会自动使用登录表单提交过来的用户名来调用以上loadUserByUsername()方法,并得到UserDetails类型的对象,此对象中应该包含用户的相关信息,例如密码、账号状态等,接下来,Spring Security会自动使用登录表单提交过来的密码与UserDetails中的密码进行对比,且判断账号状态,以决定此账号是否能够通过认证。

所以,重写以上方法:

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    // 假设存在可用的账号信息:用户名(root),密码(123456)
    if ("root".equals(s)) {
        UserDetails userDetails = User.builder()
                .username("root")
                .password("123456")
                .disabled(false)
                .accountLocked(false)
                .accountExpired(false)
                .credentialsExpired(false)
                .authorities("暂时给个山寨权限,暂时没有作用,只是避免报错而已")
                .build();
        return userDetails;
    }
    return null;
}

**提示:**当项目中存在UserDetailsService类型的组件对象时,Spring Security框架不再提供临时的账号(用户名为user密码为启动项目时的UUID值的账号)!

**注意:**Spring Security在处理认证时,要求密码必须经过加密码处理,即使你执意不加密,也必须明确的表示出来!

SecurityConfiguration中,通过@Bean方法配置PasswordEncoder,并返回NoOpPasswordEncoder的对象,表示“不对密码进行加密处理”:

@Bean
public PasswordEncoder passwordEncoder() {
    return NoOpPasswordEncoder.getInstance();
}

完成后,重启项目,通过/login可以测试访问。

使用数据库中的账号数据实现登录

需要实现“根据用户名查询用户的登录信息”,需要执行的SQL语句大致是:

select id, username, password, enable from ams_admin where username=?

在项目的根包下创建pojo.vo.AdminLoginInfoVO类:

@Data
public class AdminLoginInfoVO implements Serializable {
    private Long id;
    private String username;
    private String password;
    private Integer enable;
}

AdminMapper.java接口中添加抽象方法:

AdminLoginInfoVO getLoginInfoByUsername(String username);

AdminMapper.xml中配置以上抽象方法映射的SQL:

<select ...></select>

<sql></sql>

<resultMap></resultMap>

AdminMapperTests中编写并执行测试:

接下来,在UserDetailsServiceImpl中,先自动装配AdminMapper对象,然后,调整loadUserByUsername()方法:

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    // 使用参数s作为参数,调用AdminMapper对象的getLoginInfoByUsername()方法执行查询
    // 判断查询结果是否为null
    // 是:无此用户名对应的账号信息,返回null
    
    // 返回UserDetails对象
    // username:来自查询结果
    // password:暂时写死为123456,后续再改成来自查询结果
    // disable:来自查询结果中的enable,判断enable是否为0
    // accountExpired等:参考此前的Demo,将各值写死
}

完成后,可以使用数据库中的账号测试登录(暂时不方便测试密码)。
tLoginInfoByUsername()方法执行查询
// 判断查询结果是否为null
// 是:无此用户名对应的账号信息,返回null

// 返回UserDetails对象
// username:来自查询结果
// password:暂时写死为123456,后续再改成来自查询结果
// disable:来自查询结果中的enable,判断enable是否为0
// accountExpired等:参考此前的Demo,将各值写死

}


完成后,可以使用数据库中的账号测试登录(暂时不方便测试密码)。




#### 密码为什么需要加密

如果未加密,将密码的原文(原始密码)直接存入到数据库中,可以被轻松获取账户的关键信息!

以目前主流的网络结构和技术,通常,密码加密主要防范的是内部工作人员(能够接触到服务器的人员)!

需要注意:即使密码加密了,也要防范相关的内部工作人员,例如程序员!

#### 如何对密码进行加密

直接使用现有的某种算法,也就是说,不会自行设计某个算法!

#### 使用什么算法对密码进行加密

一定**不可以**使用**加密算法**!因为所有加密算法都是可以被逆向运算的,也就是说,可以根据加密得到的结果,进行反向运算,还原出原始密码!通常,加密算法仅用于保障数据在传输过程中的安全!

在对密码进行加密处理并存入到数据库中时,应该使用**不可逆**的算法!许多**哈希算法**,或基于哈希算法的**消息摘要算法**都是不可逆的!

#### 关于消息摘要算法

典型的消息摘要算法有:

- SHA(Secure Hash Algorithm)家族算法
  - SHA-1(160位算法)
  - SHA-256(256位算法)
  - SHA-384(384位算法)
  - SHA-512(512位算法)
- MD(Message Digest)系列算法
  - MD2(128位算法)
  - MD4(128位算法)
  - MD5(128位算法)

消息摘要算法原本是用于验证接收方所接收的数据与发送方所发出的数据是否一致。

消息摘要算法有几个典型特征:

- 如果消息相同,则摘要一定相同
- 如果消息不同,则摘要极大概率会不同
  - 必然存在n个不同的消息,摘要完全相同
- 使用同一种算法时,无论消息长度是多少,摘要的长度是固定的

#### 在项目中使用MD5算法

在Spring框架中,提供了`DigestUtils`,可以非常便利的使用MD5算法将消息处理为摘要:

```java
public class Md5Tests {

    @Test
    void encode() {
        String rawPassword = "123456";
        String encodedPassword = DigestUtils.md5DigestAsHex(
                rawPassword.getBytes());
        System.out.println("原文:" + rawPassword);
        System.out.println("密文:" + encodedPassword);
    }

}

算法位数对安全性的影响

以MD5算法为例,它是128位的算法,即其运算结果是由128个二进制位组成的,所以,其运算结果的排列组件有2的128次方种,这个数字转换成十进制是:340282366920938463463374607431768211456。

理论上,使用MD5算法时,要想找到2个不同的消息运算出相同的摘要,概率应该是340282366920938463463374607431768211456分之1!或者,也可以认为,你至少需要运算340282366920938463463374607431768211456次,才可以找到2个不同的消息运算出相同的摘要。

相比之下,更高位数的算法,理论上,更难找出不同的消息运算出相同的摘要!

一般情况下,由于MD5的安全系数已经较高,所以,不一定需要使用位数更高的算法!

关于消息摘要算法的破解 – 学术

当2个不同的消息,运算出相同的摘要,从学术上,称之为“碰撞”。

理论上,128位的算法,其碰撞概率应该是2的128次方分之1。

关于消息算法的破解,主要是研究其碰撞概率,是否可以使用更少次数的运算实现碰撞!而不是尝试根据摘要进行逆向运算还原出消息!

目前,SHA-1算法已经被视为不安全的算法,它是160位算法,经过研究,只需要经过2的60几次方的运算就可以发生碰撞,即SHA-1的安全系数与60几位的算法几乎相当。

关于消息摘要算法的“破解” – 根据摘要得到消息

网上有许多平台可以做到“根据密文还原出原文”,这些平台都是记录大量的原文与密文的对应关系,当尝试“破解”时,本质上是在做查询操作,大概是:

select 原文 from 数据表 where 密文=?

例如,某平台明确的说明了:

本站针对md5、sha1、sha256等全球通用公开的加密算法进行反向查询,通过穷举字符组合的方式,创建了明文密文对应查询数据库,创建的记录约90万亿条,占用硬盘超过500TB,查询成功率95%以上,很多复杂密文只有本站才可查询。本站专注于各种公开算法,已稳定运行17年。

如果密码可以使用全部的可打印字符,7位长度的密码的排列组合有约70万亿种,8位长度的密码的排列组件在此基础上需要乘以95,则以上平台不可能记录8位长度的所有明文密文的对应关系!也就是说,只要原始密码的长度达到8位,这些平台就可能无法根据密文查询出原文,原始密码的长度越长,或原始密码的强度越高(由多种元素组成,例如大小写字母、数字、标点符号),被这些平台收录的可能性就越低!

如何进一步保障用户的密码安全 – 加盐

盐值的本质就只是一个外部人员很难预测到的字符串,它将作用于处理加密过程中,例如:

// 以下1行定义了盐值
String salt = "fsd4W87i78oiAsUu43IEF";


String rawPassword = "123456";
String encodedPassword = DigestUtils.md5DigestAsHex(
        (rawPassword + salt).getBytes());
//       ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 将原始密码和盐值一起被处理

System.out.println("原文:" + rawPassword);
System.out.println("密文:" + encodedPassword);

当然,盐值应该如何使用,也没有明确的规定,你可以:

String encodedPassword = DigestUtils.md5DigestAsHex(
        (rawPassword + salt).getBytes());

或者:

String encodedPassword = DigestUtils.md5DigestAsHex(
        (salt + rawPassword).getBytes());

甚至:

String encodedPassword = DigestUtils.md5DigestAsHex(
        (salt + rawPassword + salt + rawPassword + salt + salt).getBytes());

总而言之,使用盐的目的是”使得被MD5运算的原始数据变得更加复杂“。

你甚至可以使用随机的盐值,例如:

String salt = UUID.randomUUID().toString(); // 使用UUID作为盐值
String rawPassword = "123456";
String encodedPassword = DigestUtils.md5DigestAsHex(
        (rawPassword + salt).getBytes());

使用随机盐时必须注意:你需要将随机的盐值保存下来,否则,后续你将无法验证密码!

至于如何保存,方式有许多,例如在数据表中添加新的字段来保存盐值,或者,把盐值直接作为密码的一部分,例如:

String salt = UUID.randomUUID().toString();
String rawPassword = "123456";
String encodedPassword = DigestUtils.md5DigestAsHex(
        (rawPassword + salt).getBytes()) + salt;
System.out.println("盐值:" + salt);
System.out.println("原文:" + rawPassword);
System.out.println("密文:" + encodedPassword);

密码加密原则 – 小结

关于密码加密处理:

  • 不可以使用加密算法,只能使用消息摘要算法或其它哈希算法
    • 不建议使用SHA-1
  • 应该要求用户使用更长的、强度更高的密码,避免容易被反查(根据密文查询得到原文)
  • 应该进行加盐处理
  • 你还可以使用多重加密(使用同一个算法,或不同算法,对数据进行反复运算)
  • 可以考虑使用位数更长的算法(在MD5的基础上,改为使用SHA-256 / SHA-384 / SHA-512)

**注意:**无论你综合使用以上哪些做法,最终,可能都无法避免内部人员泄密(算法、加密参数、加密过程、密文都是破解时的已知条件)导致的穷举式的暴力破解,而BCrypt算法是被设计得运算效率极低的算法,可以非常有效的避免被暴力破解。

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

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

相关文章

Feign Ribbon Hystrix 三者关系

在微服务架构的应用中&#xff0c; Feign、Hystrix&#xff0c;Ribbon 三者都是必不可少的&#xff0c;可以说已经成为铁三角。 Feign 介绍 Feign 是一款Java语言编写的 HttpClient 绑定器&#xff0c;在 Spring Cloud 微服务中用于实现微服务之间的声明式调用。Feign 可以定…

IIC子系统

文章目录引言一、I2C 总线驱动框架二、I2C驱动框图(重点)三、I2C 子系统软件框架3.1 I2C子系统的4个关键结构体3.2 I2C总线与平台总线的结合3.3 在设备树信息添加i2c从设备3.4 新增加i2c从设备四、i2c driver驱动的编写4.1 陀螺仪和加速度工作原理4.2 mpu6050的寄存器信息和设置…

Synchronized的锁升级过程

Synchronized的锁升级过程 synchronized锁升级过程&#xff1a;在synchronized中引入了偏向锁、轻量级锁、重量级锁之后&#xff0c;当前具体使用的是synchronzed中的那种类型锁&#xff0c;是根据线程竞争激烈程度来决定的。 偏向锁&#xff1a;在锁对象的对象头中记录一下当…

中间件之Kafka实用篇

目录标题一、一些定义&#xff08;一&#xff09;设计kafka的初衷&#xff08;二&#xff09;消息的持久化&#xff08;三&#xff09;sendfile 技术&#xff08;零拷贝&#xff09;二、获取kafka三、卡夫卡客户端工具四、kafka核心API&#xff08;功能&#xff09;五、spring …

阶段十:总结专题(第三章:虚拟机篇)

阶段十&#xff1a;总结专题&#xff08;第三章&#xff1a;虚拟机篇&#xff09;Day-第三章&#xff1a;虚拟机篇1. JVM 内存结构2. JVM 内存参数3. JVM 垃圾回收4. 内存溢出5. 类加载6. 四种引用7. finalizeDay-第三章&#xff1a;虚拟机篇 1. JVM 内存结构 要求 掌握 JVM…

Spring Cloud Alibaba全家桶(三)——微服务负载均衡器Ribbon与LoadBalancer

前言 本文为 微服务负载均衡器Ribbon与LoadBalancer 相关知识&#xff0c;下边将对什么是Ribbon&#xff08;包括&#xff1a;客户端的负载均衡、服务端的负载均衡、常见负载均衡算法&#xff09;&#xff0c;Nacos使用Ribbon&#xff0c;Ribbon内核原理&#xff08;包括&#…

Qt::QOpenGLWidget 渲染天空壳

在qt窗口中嵌入opengl渲染天空壳和各种立方体一 学前知识天空壳的渲染学前小知识1 立方体贴图 天空壳的渲染就是利用立方体贴图来实现渲染流程2 基础光照 光照模型3 opengl帧缓冲 如何自定义帧缓冲实现后期特效4 glsl常见的shader内置函数 glsl编程常用的内置函数二 shader代码…

部署运行ai智障写作记录【ChatRWKV】

文章目录前言一、环境安装1.python环境&#xff1a;Python 3.10。2.安装一些 pip 库numpy 、tokenizers 、prompt_toolkit3.安装pytorch 1.13.1CUDA 11.7二、运行记录1、下载代码2、下载训练参数3、编辑代码运行总结前言 看到知乎一篇教程&#xff0c; 大佬自己弄得ai小说续写…

AI环境搭建步骤(Windows环境)

1. 安装好Anaconda3版本(1) 安装链接&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/?CM&OD本文使用Anaconda3下载链接&#xff1a;Anaconda5(2) 注意安装anaconda时一定要把环境变量加入windows环境中。要没有勾选&#xff0c;安装完后还有手动加入…

线性代数学习-2

线性代数学习-2矩阵消元消元回代消元矩阵置换矩阵逆矩阵本文转载于https://herosunly.blog.csdn.net/article/details/88713747 该文章本人认为十分有用&#xff0c;便自己敲一遍笔记加固印象原文链接 原文这个笔记感觉比我老师讲的更加透彻&#xff0c;清晰。很好的展示了线性…

车辆热管理测试方案

车辆热管理是在能源危机出现、汽车排放法规日益严格以及人们对汽车舒适性要求更高的背景下应运而生的。将各个系统或部件如冷却系统、润滑系统和空调系统等集成一个有效的热管理系统&#xff1b;控制和优化车辆的热量传递过程&#xff0c;保证各关键部件和系统安全高效运行&…

《C++ Primer Plus》(第6版)第5章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第5章编程练习《C Primer Plus》&#xff08;第6版&#xff09;第5章编程练习1. 计算闭区间内的整数和2. 重新编写程序清单5.43. 累加4. 投资价值5. 销售情况6. 销售情况27. 汽车8. 统计单词数量9. 统计单词数量210. 嵌套循环《…

(五十)大白话深入研究索引之前,先来看看磁盘数据页的存储结构

前面我们已经给大家把MySQL数据库的部分内核原理&#xff0c;更新语句的执行原理&#xff0c;事务原理以及锁原理&#xff0c;都初步的讲给大家听了&#xff0c;同时还穿插了一些相关的数据库性能优化的案例&#xff0c;相信现在大家已经对数据库执行增删改语句的原理有了较为深…

小程序容器与微服务架构:提高应用程序开发效率和部署速度的利器

随着移动互联网的发展&#xff0c;小程序已经成为了一种非常流行的应用方式&#xff0c;它可以在不安装任何应用的情况下&#xff0c;直接在移动终端设备&#xff08;如&#xff1a;App&#xff0c;iPad等&#xff09;中运行。微服务架构则是一种的分布式系统架构&#xff0c;可…

三维数据可视化软件,可视化地图是用什么做的?

可视化地图是用什么做的&#xff1f;数据可视化地图是一种利用空间数据来表现地理信息的方式&#xff0c;能够为人们提供关于地理信息的准确、直观的可视化图形&#xff0c;以便更好地理解相关信息。数据地图可以最直观的表达出数据之间的空间关系&#xff0c;因此在很多数据分…

【组织架构】中国铁路兰州局集团有限公司

1 公司简介 中国铁路兰州局集团有限公司&#xff0c;是中国国家铁路集团有限公司管理的18个铁路局集团有限公司之一&#xff0c;简称“兰局”。经过59年的发展&#xff0c;现已成为西北地区最大的交通运输企业之一&#xff0c;形成了以兰州为枢纽&#xff0c;由陇海铁路、包兰铁…

前端Cookie基础知识

一、简介 ​ Cookie&#xff08;也称为HTTP Cookie、Web Cookie、浏览器 Cookie等等&#xff09;是服务器发送到用户浏览器并保存在本地的一小块数据&#xff0c;该数据通常是用户账号相关的信息&#xff0c;不同浏览器对Cookie的数量和大小限制不同&#xff0c;但一般来说&am…

centos8安装

本文由个人总结&#xff0c;如需转载使用请标明原著及原文地址 1.下载镜像 1.1阿里镜像 可以在阿里云的镜像库里下载&#xff0c;阿里centos8只保留了8.5.2111如果需要别的版本看1.2 http://mirrors.aliyun.com/centos/8/isos/x86_64 1.2其他版本的镜像 下好镜像的可以跳过…

2023年1月京东“白酒”品类销售数据出炉,五粮液表现较好

鲸参谋电商数据监测的2023年1月份京东“白酒”品类销售数据出炉&#xff01; 根据鲸参谋电商数据显示&#xff0c;2023年1月&#xff0c;京东平台上白酒的销量共计980万&#xff0c;环比增长约180%&#xff0c;同比去年增长约13%&#xff1b;销售额将近69亿&#xff0c;环比增长…

2021年全国职业院校技能大赛(中职组)网络安全竞赛试题A(1)

2021年全国职业院校技能大赛&#xff08;中职组&#xff09; 网络安全竞赛试题 &#xff08;1&#xff09; 这里是21的试题就以刷题为主&#xff0c;方法可能就不那么详细&#xff0c;如果是新题会详细过程&#xff0c;其他的详细过程可以看22的试题 目录 2021年全国职业院校…