转自: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. Selenium 自动化测试中对页面元素的value比较验证 java语言

    源代码: public boolean verifyText(String elementName, String expectedText) {String actualText = getValu ...

  2. python爬取北京政府信件信息01

    python爬取,找到目标地址,开始研究网页代码格式,于是就开始根据之前学的知识进行爬取,出师不利啊,一开始爬取就出现了个问题,这是之前是没有遇到过的,明明地址没问题,就是显示网页不存在,于是就在百度 ...

  3. Spring Boot入门学习必知道企业常用的Starter

    SpringBoot企业常用的 starter SpringBoot简介 SpringBoot运行 SpringBoot目录结构 整合JdbcTemplate @RestController 整合JS ...

  4. 在 Intenseye,为什么我们选择 Linkerd2 作为 Service Mesh 工具(Part.1)

    在 Intenseye,我们 follow(跟随) trends(趋势) & hype(最被炒作) 的技术,并在使用时应用最佳实践. 我们在用 Scala.Go.Python 等编写的 Kub ...

  5. 高德纳/Donald Ervin Knuth

    丸了丸了这位就是我人生的第一位爱豆了owo 感觉他的经历,气质都是我期望的类型呀. 即使没有人家的智商和绝顶天赋,也不断向彼努力吧. 从小喜欢音乐,会多种乐器(管风琴) 其实长得人高马大,高中校篮球队 ...

  6. Receiver class com.mchange.v2.c3p0.impl.NewProxyResultSet does not define or inherit an implementation of the resolved method 'abstract boolean isClosed()' of interface java.sql.ResultSet.

    背景: Mayabtis+springboot项目,连接数据库发生异常 报错内容: java.lang.AbstractMethodError: Receiver class com.mchange. ...

  7. ODOO里视图开发案例---定义一个像tree、form一样的视图

    odoo里视图模型MVC模式: 例子:在原来的视图上修改他: var CustomRenderer = KanbanRenderer.extend({ ....});var CustomRendere ...

  8. 第十二篇 -- 关于U盘制作启动盘后在本机上显示不出来的解决方案

    喜欢玩电脑的朋友应该都重装过系统,最常用的就是用U盘装系统.以前装系统都没问题,不过偶然一次发现了一个问题,就是那个被制作成启动盘的U盘,插在本机上只能显示EFI启动文件部分,而其他空间全都显示不出来 ...

  9. Django JSONField/HStoreField SQL注入漏洞(CVE-2019-14234)

    复现 访问http://192.168.49.2:8000/admin 输入用户名admin ,密码a123123123 然后构造URL进行查询,payload: http://192.168.49. ...

  10. 洛谷P2858题解

    这是一道裸的第二类区间DP(由已知区间向外扩展)题. 首先定义 \(f_{i,j}\) 为最后 \(j-i+1\) 个数取 \([i,j]\) 这个区间时,\([i,j]\) 这个区间可以产生的最大价 ...