转自:https://blog.csdn.net/weixin_37689658/article/details/92752890

1、基本配置使用

(1)创建配置类

创建一个配置类SecurityConfig继承自WebSecurityConfigurerAdapter,重写里面的configure(HttpSecurity http)这个方法,配置好需要认证的登录url,以及提交表单的url,这里除了登录url不需要认证之外,其他的url都需要认证才能访问,并且formLogin表名这是一个表单提交,loginprocessingUrl中是设置的提交登录表单的url。

@Override
protected void configure(HttpSecurity http) throws Exception {
.formLogin()
.loginPage("/authentication/require") //指定没有认证时跳转到的认证url
.loginProcessingUrl("/authentication/form") //提交登录表单的url
.and()
.authorizeRequests()
.antMatchers("/authentication/require").permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}

(2)获取认证信息

我们需要继承一个UserDetailSevice接口并且加入到容器中,实现loadUserByUsername方法,里面的逻辑通常是从数据库查找出对应用户名的密码然后构造一个UserDetail对象,spring security会根据返回的这个带有正确用户信息的对象和前台传过来的用户名密码进行比对来判断是否认证通过。

/**
* 表单登录的时候会调用loadUserByUsername来验证前端传过来的账号密码是否正确
*/
@Component
public class MyUserDetailService implements UserDetailsService { private Logger logger = LoggerFactory.getLogger(MyUserDetailService.class); @Autowired
private PasswordEncoder passwordEncoder; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
logger.info("登录用户名===========" + username);
//这里需要去数据库查询用户的账号密码来比对是否正确,以及账号是否过期等等
String password = passwordEncoder.encode("123456");
logger.info("数据库密码是==============" + password);
return new User(username, password,
true,
true,
true,
true,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}

 

这样配置好的话,比如说我们访问一个一个http://localhost:8080/user的接口,那么spring security 发现配置中这个接口是需要拦截的,并且当前的请求还没有通过认证,就会重定向到loginPage设置的这个接口或者页面中去。当我们调用loginProcessingUrl这个接口去提交表单的时候,如果通过了认证,那么就会重定向到原来我们想要访问的接口中去了,如果认证不成功,那么就出现认证失败等信息。

那么对于这个过程,spring security内部的流程到底是怎样的尼?我们先通过一张图来看。

我们可以看到在spring security内部其实是通过一个过滤器链来实现认证流程的,比如说这里的UsernamePasswordAuthenticationFilter就是拦截我们通过表单提交接口提交的用户名和密码,如果是Basic提交的话,就会被BasicAuthenticationFilter拦截,最后的橙色FilterSecurityInterceptor是首先判断我们当前请求的url是否需要认证,如果需要认证,那么就看当前请求是否已经认证,是的话就放行到我们要访问的接口,否则重定向到认证页面。

2、认证流程

这里已表单提交为例,当我们提交表单时,UsernamePasswordAuthenticationFilter首先会拦截请求,而UsernamePasswordAuthenticationFilter是继承于AbstractAuthenticationProcessingFilter的,在这个抽象类中已经定义好了doFilter的方法,而里面有一个attemptAuthentication方法是由子类实现的。所以当提交表单时spring security会发现这个一个表单提交,然后就调用了UsernamePasswordAuthenticationFilter的doFilter方法

然后我们来看 UsernamePasswordAuthenticationFilter里面重写的这个方法

然后我们可以看到首先是创建了一个UsernamePasswordAuthenticationToken对象,把用户名和密码传进去,再调用了getAuthenticationManager().authentication()方法,并把 UsernamePasswordAuthenticationToken对象传进去,那么这个AuthenticationManager是什么尼,其实它是一个接口

我们这里要看的是它的实现类ProviderManager,进去找到它的authenticate方法

其实这个ProviderManager就是管理所有的Provider对象的,通过for循环遍历找到适合的provider对象来调用其authenticate方法,那么provider对象又是什么东西?其实它也是一个接口

可以看到它的实现类有很多,我们这里主要来看DaoAuthenticationProvider这个实现类,但是在这个类中并没有找到authenticate方法,那么我们来它的父类AbstractUserDetailAuthenticationProvider里面来看下

里面调用了一个子类实现的方法,我们看这个子类的这个方法l

里面拿到我们之前加入到容器中的userDetailService然后调用loadUserByUsername方法拿到我们包含数据库用户信息的UserDetail对象,并且捕获用户名找不到等异常,所以这个方法就是来获取我们之前定义的userDetailService返回的UserDetail。

回到其父类中去,父类拿到了UserDetail对象,对这个对象进行了一系列的判断

首先我们来看下前置判断

里面就是调用了UserDetail对象一些实现方法进行判断,比如说账户是否锁定,账户是否能用,账户是否过期的判断,判断通过后来到了密码判断

在判断了密码是否正确之后,后置判断就是来判断密码是否过期了,

前置判断判断账户异常问题,然后到密码判断,最后到密码是否过期判断,因为你登录先看你账户是否有异常才能,有异常的话就不进行密码判断了,密码正确也要看密码是够过期 ,所以这三个操作合乎常理。

判断都没问题之后,最后返回了一个authentication对象,这里把用户名,密码,权限都传到UsernamePasswordAuthenticationToken中去,因为所有判断都没问题,这些信息都是正确的了。

3.认证结果如何在多个线程中共享?

首先,我们还是先来看一张图

当请求过来的时候都会最先经过一个叫SecurityContextPersistenceFilter的过滤器,这个过滤器的作用就是在请求经过的时候检查session中是否有认证的authentication对象,如果有的话就把它放进一个叫securityContext ,然后再交给securityContextHolder处理

看一下securityContext

它是一个接口,由子类SecurityContextImpl实现,里面就是一个authentication属性,所以它的作用就是包装了authentication

接下来再看一下securityContextHolder

里面的getContext,clearContext方法都是使用的一个叫 SecurityContextHolderStrategy对象,点进去看一下这个对象

我们发现它又是一个接口,我们看它的实现类ThreadLocalSecurityContextHolderStrategy

里面只有一个ThreadLocal对象,放的是SecurityContext,我们知道ThreadLocal有线程隔离的作用,每一个对象在ThreadLocal中都是线程级别的。

接着我们回到securityContextpersistenceFilter中去看里面的doFilter方法

有一个loadContext方法是加载出来SecurityContext对象的,那么它是怎么加载的?点进去

它是一个接口,看它的实现类HttpSessionSecurityContextRepository

所以上面请求经过securityContextpersistenceFilter就是先从判断session是否有SecurityContext,有的话就放进当前线程中

那么响应的时候做什么?这里直接给出

那么认证成功后,是谁把认证对象放在放在当前请求中的?答案就是FilterSecurityInterceptor,FilterSecurityInterceptor会判断当前请求的url是否要拦截,要拦截的话如果当前用户没有经过认证,那么就跳转到认证页面,如果认证了就直接放行,并且把认证信息放在当前线程中。

总的流程:一个请求过来时通过各个过滤器,最后通过FilterSecurityInterceptor来判断这个请求url是否是不需要验证的,如果是
就直接访问到我们的接口api,如果不是的话,再判断当前请求线程中是否有authentication的认证对象,如果有就放行,如果没有就返回登录页面(比如这里我们设置的是登录表单的方式),来到登录页面输入账号密码登录后就会来到    UsernamePasswordAuthenticationFilter,经过一系列的操作,最后验证成功就会把认证对象authentication放进securityContext中,然后FilterSecurityInterceptor判断到当前请求线程中这个认证对象就放行,返回的时候最后会通过securityContextpersistenceFilter,判断当前线程是否有securityContext,如果有就放进session,那么下次再请求这个url的时候会首先通过securityContextpersistenceFilter这个过滤器,判断session中是否有securityContextduxiiang,如果有就放进当前请求线程中,然后最后经过FilterSecurityInterceptor时再判断当前请求线程是否有认证对象,由于最前面经过securityContextpersistenceFilter,已经从session中把认证对象放进了当前请求线程中,所以FilterSecurityInterceptor会直接放行,这样就访问到我们的接口api。

【权限管理】Spring Security 执行流程的更多相关文章

  1. 03 spring security执行流程分析

    spring security主要是依赖一系列的Filter来实现权限验证的,责任链设计模式是跑不了的.下面简单记录一下spring操作这些Filter的过程. 1. WebSecurityConfi ...

  2. 一文读懂Spring MVC执行流程

    说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图:   ...

  3. Java——一文读懂Spring MVC执行流程

    说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...

  4. spring boot:spring security用mysql实现动态权限管理(spring boot 2.3.3)

    一,动态权限管理的优点和缺点 1,优点: 因为控制权限的数据保存在了mysql或其他存储系统中, 可以动态修改权限控制,无需改动代码和重启应用,  权限变更时灵活方便 2,缺点: 权限的设置需要保存在 ...

  5. spring boot:spring security用mysql数据库实现RBAC权限管理(spring boot 2.3.1)

    一,用数据库实现权限管理要注意哪些环节? 1,需要生成spring security中user类的派生类,用来保存用户id和昵称等信息, 避免页面上显示用户昵称时需要查数据库 2,如果需要在页面上显示 ...

  6. 权限开发 spring security 3.0.7 序列1 数据库脚本

    spring  security  3 细粒度权限控制第一篇,关于权限的初始化测试数据库脚本. 空间脚本: drop user FrameworkTest cascade; drop tablespa ...

  7. 使用IDEA搭建一个Spring + AOP (权限管理 ) + Spring MVC + Mybatis的Web项目 (零配置文件)

    前言: 除了mybatis 不是零配置,有些还是有xml的配置文件在里面的. 注解是Spring的一个构建的一个重要手段,减少写配置文件,下面解释一下一些要用到的注解: @Configuration  ...

  8. Spring Security认证流程分析--练气后期

    写在前面 在前一篇文章中,我们介绍了如何配置spring security的自定义认证页面,以及前后端分离场景下如何获取spring security的CSRF Token.在这一篇文章中我们将来分析 ...

  9. spring security执行流程图

    今天看到非常多人转载了这篇文章,这里备注一下.原文来自CSDN我的博客. 近期在研究spring security的配置,研究了一个星期了,在官网看了下.仅仅配置出来了简单的登录,但不知如何从数据库读 ...

随机推荐

  1. 【LeetCode】344. 反转字符串

    344. 反转字符串 知识点:字符串; 双指针 题目描述 编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改 ...

  2. 以初学者的角度理解:SQL实现关系除法

    以初学者的角度理解:SQL实现关系除法 相信各位在学习SQL的时候,由于没有一家SQL语言提供除法命令而只能自己写一个.而网上大多就是四步骤加一个模板: select distinct A.X fro ...

  3. 第三篇 -- SpringBoot打包成jar包

    本篇介绍怎么将SprintBoot项目打包成jar包. 第一步:点击IDEA右侧的maven. 第二步:双击package,然后就会开始打包,当出现build success时,就打包成功了,一般在t ...

  4. 福昕foxit phantom pdf高级编辑器企业版10.1 pro安装破解教程

    本文提供福昕foxit phantom pdf高级编辑器企业版10.1的安装教程.pj教程,可以使用全部功能,注意的是此方法对个人版无效. 没有必要再尝试别的文章,仅看这一篇即可!别的文章亲测是通过修 ...

  5. xampp搭建开源项目iwebshop后,服务器重启后再启动xampp显示组件都启动ok,但是实际启动失败解决办法

    最近用xampp搭建了开源商城项目iwebshop,刚搭建完没问题,可是周一来因为服务器重启了,我再启动xampp,显示组件都启动ok了,但是用linux命令查看相关组件的进程时,发现实际没启动起来, ...

  6. Verilog定点数计算

    https://blog.csdn.net/maxwell2ic/article/details/80620991 https://blog.csdn.net/mdpsdhr/article/deta ...

  7. AWS 安全信息泄露-----21天烧了27万

    安全问题一直都是个老生常谈的话题,对于我们做IT的来说,是更为重视的.从使用开发工具的是否授权合规,到从事的工作内容是否合法.我们都应该认真的思考一下这些问题,毕竟我们要靠IT这门手艺吃饭. 2021 ...

  8. 配置 Nvidia GPU 主机的运行环境

    在 Linux 主机上配置了很多次 Cuda/CuDNN 的运行环境,在此记录下用到的脚本命令以复用. 特别提醒,先了解清楚 GPU 卡的型号,查清与主机 Linux 内核兼容的驱动程序.Cuda 和 ...

  9. RHCSA_DAY04

    软连接与硬连接 Linux中的链接文件类似于windows中的快捷方式 软连接特点:软连接可以跨分区,可以对目录进行链接,源文件删除后,链接文件不可用 软连接命令格式:ln -s 源文件路径  目标路 ...

  10. C++通讯录管理系统(添加联系人,显示联系人,删除联系人,查找联系人,修改联系人,清空联系人,退出通讯录)

    1 /** 2 * ProjectNmae:通讯录管理系统 3 * 功能: 4 * 添加联系人:向通讯录添加新人 5 * 显示联系人:显示通讯录中的所有联系人信息 6 * 删除联系人:按照姓名进行删除 ...