SpringSecurity学习总结(三更草堂)

SpringSecurity安全框架的核心功能认证授权

        认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户。

        授权:经过认证后判断当前用户是否具有进行某个操作权限。

        一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多,因为相比与SpringSecurity,Shiro的上手更加的简单。

二、入门案例:

2.1、创建Springboot项目:勾选SpringSecurity依赖

在SpringBoot项目中使用SpringSecurity我们只需要引入依赖即可实现入门案例:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

        引入依赖后,启动Springboot应用,尝试去访问hello接口就会自动跳转到一个SpringSecurity的默认登陆页面,默认用户名是user, 密码会输出在控制台,必须登陆之后才能对接口进行访问:

@RestController
public class SecurityController {@RequestMapping("/hello")public String helloController(){return "欢迎使用SpringSecurity";}
}
2.2、启动应用,访问接口:

        当我们访问:http://localhost:8080/hello 时,会自动跳转到默认的登陆页面:

2.3、入门案例中 SpringSecurity 的流程:

        SpringSecurity 的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器 ,这里我们可以看看入门案例中的过滤器:图中只展示了核心过滤器,其它的非核心过滤器没有展示。

        UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名、密码后的登陆请求。入门案例的认证工作主要有它负责。

    ExceptionTranslationFilter: 处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException 。

        FilterSecurityInterceptor: 负责权限校验的过滤器

 我们可以通过Debug查看当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序:

入门案例中的SpringSecurity过滤器链里有15个过滤器:

        {DefaultLoginPageGeneratingFilter@6504} 这个Filter功能是用来显示默认的登录页,如果说你不想要默认登录页,到时候不要加他就可以了,

        {DefaultLogoutPageGerneratingFilter@6505}这个Filter功能是用来显示默认的注销页面

2.4、入门认证流程详解:

概念速查:

Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。它用来表示的是当前访问系统的用户,可以在里面封装一些用户的相关信息,比如说用户名、密码,然后包括用户的一些权限都可以。但是在这个情况下,你看他只提交了用户名、密码,那他装的对象里面也只有用户名和密码信息

AuthenticationManager接口:定义了认证Authentication的方法

UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。会把这些用户信息权限信息又封装成一个UserDetails对象,这也是一个接口,它的核心提供了用户信息,我们可以把查到的用户的一些信息封装到这个接口的一个对象里面去。

UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
 

2.5、入门案例的缺点分析:

        1、在我们前后端分离的项目中,我们不需要springsecurity提供的默认登录页,给它删除,我们需要自定义登录接口;

        2、入门案例里面用户名和密码,用户名默认为user,密码是它随机生成的,这肯定是不行的。我们应该是让他去数据库里面去进行用户名、密码的校验;

        3、入门案例它是基于session去实现这种登录。前后端不分离的时候可以用session,前后端分离,就不能使用session了,当用户的用户名、密码校验成功后,我们应该①:以用户id生成jwt,作为token响应给前端;② 同时以用户id作为key,用户信息作为value,存入Redis中;(实际项目中用不用 "用户id" 作为jwt、作为key看具体的项目需求)

        4、当我们校验用户有没有权限去访问当前他所请求的这个资源时,我们应该去获取请求头中的token进行解析,去判断有没有权限访问当前资源 

三、自定义登录的认证:

  实际前后端分离的项目中,去进行认证,核心其实依赖的就是token,你可以理解成它是一个加密之后的一个字符串,我通过前端是否携带这个token,去判断你是不是我系统的用户、你究竟是哪一个用户,这是它的一个核心思路

3.1、自定义的登录认证需要实现两大功能:登录、校验

登录

​         ①自定义登录接口:

                 把用户输入的用户名和密码封装成Authentication对象

​                 调用ProviderManager的authenticate()方法进行认证

                 如果认证没通过给用户对应的提示信息

                 如果认证通过则生成jwt作为token返回给前端,并且把用户信息存入redis中

​         ②自定义UserDetailsService接口的实现类

​                 在这个实现类中去查询数据库

校验:

​         ①定义Jwt认证过滤器

​                 获取token

​                 解析token获取其中的userid

​                 从redis中获取用户信息

​                 存入SecurityContextHolder

3.2、"自定义登录接口"的具体思路、流程:

        ①、默认情况下定义的接口,都会被我们SpringSecurity保护,要求必须认证后,才能够访问,而这个登录接口,必须设置为让SpringSecurity放行,让用户访问登录接口的时候不需要登录也能够访问,否则会相互矛盾

        ②、我们自定义一个登录接口,其实就是定义一个Controller去接受用户输入的用户名和密码,然后在Controller中去调用Service,在Service当中进行具体的业务操作,这个登录接口的请求方式为Post,所以要使用@PostMapping

         ③、具体的业务操作包括:

用户名和密码封装成Authentication对象

调用AuthenticationManager的authenticate()方法进行认证

密码加密存储PassWordEncoder

        实际项目中我们不会把密码明文存储在数据库中。
        默认使用的PasswordEncoder要求数据库中的密码格式为: {id}password。它会根据id去判断密码的加密方式,如果没加密,就是{noop}password。但是我们一般不会采用这种方式。所以需要替换PasswordEncoder。 
        我们一般使用SpringSecurity为我们提供的BCryptPasswordEncoder,我们只需要使用把BCryptPasswordEncoder对象注入Spring容器中,SpringSecurity就会使用BCryptPasswordEncoder来进行密码校验。

BCryptPasswordEncoder简介:

1 、BCryptPasswordEncoder是采用SHA-256 +随机盐+密钥对明文密码进行加密。SHA系列是Hash算法,不是加密算法,使用加密算法意味着可以解密(这个与编码/解码一样),但是采用Hash处理,其过程是不可逆的。BCrypt 是一种强哈希算法,它能很好地防止被暴力破解。

2、加密(encode):注册用户时,采用SHA-256+随机盐+密钥把用户输入的密码进行hash处理,得到密码的hash值,然后将其存入数据库中。因为每次的随机盐不同,导致对同一明文密码加密后得到的加密结果都不一样。密文中本身包含了很多信息,包括 salt 和 使用 salt 加密后的 hash。

3、密码匹配(matches):用户登录时,密码匹配阶段并没有进行密码解密(因为密码经过Hash处理,是不可逆的),而是使用相同的算法把用户输入的密码进行hash处理,得到密码的hash值,然后将其与从数据库中查询到的密码hash值进行比较。如果两者相同,说明用户输入的密码正确。

4、这正是为什么处理密码时要用hash算法,而不用加密算法。因为这样处理即使数据库泄漏,黑客也很难破解密码!


 BCryptPasswordEncoder举例:

        我们可以定义一个SpringSecurity的配置类,SpringSecurity要求这个配置类要继承WebSecurityConfigurerAdapter:

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}

 

@SpringBootTest
class Boot3SpringsecurityApplicationTests {@Autowiredprivate BCryptPasswordEncoder passwordEncoder;@Testpublic void testBCryptPasswordEncoder(){// BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();//传入密码的明文,它就会帮你进行加密,然后返回加密之后的字符串String encode1 = passwordEncoder.encode("123456");String encode2 = passwordEncoder.encode("123456");System.out.println("encode1: "+encode1);System.out.println("encode2: "+encode2);//第一个参数传入的是登录时候用户输入的密码,明文,然后和你数据库当中查到的加密后的密文比较:boolean flag1 = passwordEncoder.matches("123456",encode1);boolean flag2 = passwordEncoder.matches("123456",encode2);System.out.println("flag1为"+flag1);System.out.println("flag2为"+flag2);}}
LoginUser implements UserDetails:

到时候框架里面会调用loginUser的getPassword()方法来获取当前用户的密码之类的
 

                                

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginUser implements UserDetails {private User user;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUserName();}@Overridepublic boolean isAccountNonExpired() {return false;}@Overridepublic boolean isAccountNonLocked() {return false;}@Overridepublic boolean isCredentialsNonExpired() {return false;}@Overridepublic boolean isEnabled() {return false;}
}

自定义登录接口:

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

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

相关文章

vue3组合式函数

vue3的组合式函数的作用是封装和复用响应式状态的函数。只能在setup 标签的script标签汇总或者setup函数中使用。 普通的函数只能调用一次&#xff0c;但是组合式函数接受到响应式参数&#xff0c;当该值发生变化时&#xff0c;也会触发相关函数的重新加载。 如下 定义了一个…

Ubuntu如何配置有线网(只显示VPN和代理时)

Step 1: 将managed的值改为true Step 2&#xff1a; 加入如下的字段&#xff0c; Step 3: reboot

阿里云CentOS7安装MySQL8

创建目录 [rootnode1 ~]# mkdir /usr/local/mysql [rootnode1 ~]# cd /usr/local/mysql/ 下载安装包 到MySQL官网查看需要下载的版本&#xff0c;并获取到下载地址 https://downloads.mysql.com/archives/community/下载 [rootnode1 mysql]# wget https://downloads.mysql…

做现货白银,要直面实时行情走势!

现货白银拥有完善的交易机制&#xff0c;它每天的实时行情走势中充满着交易获利的机会&#xff0c;但不见得每一位投资者都有把握住的能力。在各种资讯都触手可及的今天&#xff0c;投资者可以轻松地获得现与货白银相关的交易技巧&#xff0c;然而交易的智慧&#xff0c;则需要…

【供应海力士H58GG6MK6GX037存储芯片

17566722766 长期供应各进口原装存储芯片&#xff1a; H58GG6MK6GX037 K3UH7H70AM-AGCL K3UHAHA0AM-AGCL H9HKNNNFBMAVAR-NEH K54GG6AYRHX263 K3UH7H70BH-AGCL K3UHAHA0BM-AGCL K3LK3K30EM-BGCN K3LK4K40BM-BGCN K3LK7K70BM-BGCP K3LK4K40CM-BGCP H9JKNNNFB3AECR-…

Redis 的常见问题及解决方案

1、性能问题&#xff1a; 当 Redis 负载过高时&#xff0c;可能会出现性能下降的情况。这可能是由于大量的并发访问、数据量过大或复杂的操作导致的。 解决方案&#xff1a;优化数据结构的使用&#xff0c;避免使用过于复杂的操作。考虑使用分布式 Redis 架构行水平扩展&#x…

Java 随笔记: 面向对象编程(二)

目录 1. 包 2. 访问修饰符 3. 封装 4. getter和setter方法 5. Java Bean 类 6. 继承 7. super 关键字 8. 方法重写 9. 多态 10. 动态绑定机制 11. Object 类 1. 包 在Java中&#xff0c;包&#xff08;package&#xff09;是一种组织代码的机制。它是一种将相关类…

基于java+SpringBoot+Vue的校园台球厅人员与设备管理系统设计与实现

基于javaSpringBootVue的校园台球厅人员与设备管理系统设计与实现 开发语言: Java 数据库: MySQL技术: SpringBoot MyBatis工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 后台展示 系统简介 整体功能包含&#xff1a; 校园台球厅人员与设备管理系统是一个为校园…

简单设计模式讲解

设计模式是在软件开发中经常使用的最佳实践&#xff0c;用于解决在软件设计中经常遇到的问题。它们提供了可重用的设计&#xff0c;使得代码更加灵活、可维护和可扩展。下面我将为你讲解几种常见的设计模式&#xff0c;并提供相应的C#代码示例。 1. 单例模式&#xff08;Single…

【docker】Dockerfile自定义镜像

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;中间件 ⛺️稳中求进&#xff0c;晒太阳 1.Dockerfile自定义镜像 常见的镜像在DockerHub就能找到&#xff0c;但是我们自己写的项目就必须自己构建镜像了。 而要自定义镜像&#xff0c;就…

算法沉淀 —— 深度搜索(dfs)

算法沉淀 —— 深度搜索&#xff08;dfs&#xff09; 一、计算布尔二叉树的值二、求根节点到叶节点数字之和三、二叉树剪枝四、验证二叉搜索树五、二叉搜索树中第K小的元素 一、计算布尔二叉树的值 【题目链接】&#xff1a;2331. 计算布尔二叉树的值 【题目】&#xff1a; …

一款比Typora更简洁优雅的Markdown编辑器神器(完全开源免费)

前言 自从Typora收费以后经常有朋友会问有没有一个好用、简洁、免费的Markdown编辑器推荐的&#xff0c;今天大姚给大家分享一款比Typora更简洁优雅的、完全开源免费&#xff08;MIT License&#xff09;Markdown编辑器神器&#xff1a;MarkText。 MarkText简介 Typora的完美替…

Java EE:多线程 —— 什么是线程,线程与进程的区别

1、线程是什么 一个线程就是一个 “执行流”。每个线程之间都可以按照顺序执行自己的代码&#xff0c;多个线程之间 “同时” 执行着多份代码。 举例说明&#xff1a; 假设一家公司要去银行办业务&#xff0c;既要进行财务转账&#xff0c;又要进行福利发放&#xff0c;还得进…

Collection与数据结构链表与LinkedList(三):链表精选OJ例题(下)

1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…

[源码] Android 上的一些快捷方式,如通知、快捷方式等

目录 一、通知0. 配置权限1. 测试发送通知代码2. 打开通知设置界面代码3. 前台服务创建常驻通知 二、快捷方式1. 测试添加动态快捷方式代码 三、开发者图块四、桌面小部件 基于jetpack compose 框架的使用代码 一、通知 参见 官方文档 0. 配置权限 <uses-permission andr…

Android仿高德首页三段式滑动

最近发现很多app都使用了三段式滑动&#xff0c;比如说高德的首页和某宝等物流信息都是使用的三段式滑动方式&#xff0c;谷歌其实给了我们很好的2段式滑动&#xff0c;就是BottomSheet&#xff0c;所以这次我也是在这个原理基础上做了一个小小的修改来实现我们今天想要的效果。…

刷题之动态规划-路径问题

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;开始刷动态规划的题目了&#xff0c;要特别注意初始化的时候给什么值。 动态规划5个步骤 状态表示 &#xff1a;dp数组中每一个下标对应值的含义是什么->dp[i]表示什么状态转移方程&#xff1a; dp[i] 等于什么1 和 2 是…

NRF52832修改OTA升级时的bootloader蓝牙MAC

NRF52832在OTA升级时&#xff0c;修改了APP的蓝牙MAC会导致无法升级&#xff0c;原因是OTA程序的蓝牙MAC没有被修改所以手机扫描蓝牙时无法连接 解决办法 在bootloader的程序里面加入修改蓝牙mac地址的代码实现原理&#xff1a; 在bootloader蓝牙广播开启之前修改蓝牙mac 通…

轻松编辑照片,无需下载!2024年最受推荐的在线PS替代工具

设计领域&#xff0c;Adobe Photoshop无疑是最受欢迎的软件之一。然而&#xff0c;PS对初学者来说可能很复杂&#xff0c;需要安装在计算机上&#xff0c;更不用说相对昂贵的价格了。这些因素使得PS在线网页替代设计工具越来越受欢迎。今天&#xff0c;我们将为您介绍一些优秀的…

[Leetcode笔记] 滑动窗口相关

前言 今天做leetcode的时候遇到一道滑动窗口相关的题目&#xff0c;题目具体内容如下&#xff1a; 思路 这道题很显然需要用到滑动窗口&#xff0c;肯定不是让你傻乎乎一遍一遍去遍历数组的内容然后遍历尝试 流程&#xff1a; 先算数组的总大小。使用while计算滑动窗口数…