SpringSecurity原理

主要过滤器链

SpringSecurity的功能主要是由一系列的过滤器链相互配合完成的。验证一个过滤器之后放行到下一个过滤器链,然后到最后。

认证流程

过滤器作用

  1. SecurityContextPersistenceFilter:会在每次请求处理之前从配置好的SecurityContextRepository中获取SecurityContext安全上下文信息,然后加载到SecurityContextHolder中,然后在该次请求处理完成之后,将SecurityContextHolder中关于这次请求的信息存储到一个“仓库”中,然后将SecurityContextHolder中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的。

  2. DefaultLoginPageGeneratingFilter:如果没有配置自定义登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

  3. BasicAuthenticationFilter:检测和处理http basic认证。

  4. UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自/login的表单action。从表单中获取用户名和密码时,默认使用的表单name属性值为username和password,这俩个值也可以通过usernameParameter和passwordParameter在配置中自定义。

    这个过滤器在表单提交登录请求之时会起作用。那么假设现在采用SpringSecurity整合Jwt,那么我需要配置一个Jwt登录认证类(继承BasicAuthenticationFilter或者继承OncePerRequestFilter都可以,因为BasicAuthenticationFilter继承了OncePerRequestFilter),重写过滤器方法。Jwt的token认证登录是需要在在采用用户名密码登录认证之前,所以在配置Jwt登录认证类的时候需要在UsernamePasswordAuthenticationFilter之前添加过滤器。

    //配置自定义过滤器 添加jwt登录授权过滤器
    //在过滤器UsernamePasswordAuthenticationFilter之前
    http.addFilterBefore(jwtAuthenticationFilter,UsernamePasswordAuthenticationFilter.class);
  5. RequestCacheAwareFilter:用来处理请求的缓存。

  6. SecurityContextHolderAwareRequestFilter:主要是包装请求对象request。

  7. AnonymousAuthenticationFilter:检测SecurityContextHolder中是否存在Authentication对象,如果不存在则为其提供一个匿名Authentication。

  8. SessionManagementFilter:管理Session的过滤器

  9. ExceptionTranslationFilter:捕获来自过滤器链的所有异常,并进行处理。但是只处理两类异常:AccessDeniedException和AuthenticationException 异常,其他的异常会继续抛出。

    如果捕获到的AuthenticationException,那么将会使用其对应的AuthenticationEntryPoint的commence()方法处理。在处理之前,ExceptionTranslationFilter先使用RequestCache将当前的HTTPServletRequest的信息保存起来,方便用户登录成功后可以跳转到之前的页面。

    可以自定义AuthenticationException的处理方法。需要实现AuthenticationEntryPoint接口,然后重写commence()方法。

    /**
    * 当未登录或者token失效时访问接口自定义的返回结果
    */
    @Component
    public class RestfulAuthorizationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/json");
    PrintWriter writer = response.getWriter();
    RespBean bean = RespBean.error("请先登录!");
    bean.setCode(401);
    writer.write(new ObjectMapper().writeValueAsString(bean));
    writer.flush();
    writer.close();
    }
    }

    如果捕获的AuthenticationDeniedException,那么将会根据当前访问的用户是否已经登录认证做不同的处理,如果未登录,则会使用关联的AuthenticationEntryPoint的commence()方法进行处理,否则将使用关联的AccessDeniedHandler的handle()方法进行处理。

    可以进行自定义AuthenticationDeniedException的处理方法。需要实现AccessDeniedHandler接口,然后重写handle()方法。

    @Component
    public class RestfulAccessDeniedHandler implements AccessDeniedHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
    response.setCharacterEncoding("utf-8");
    response.setContentType("application/json");
    PrintWriter writer = response.getWriter();
    RespBean error = RespBean.error("权限不足,联系管理员!");
    writer.write(new ObjectMapper().writeValueAsString(error));
    error.setCode(403);
    writer.flush();
    writer.close();
    }
    }
  10. FilterSecurityInterceptor:可以看做过滤器链的出口

  11. RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

SecurityContextHolder

SecurityContext对象是安全上下文信息,包括当前使用系统的用户的信息。每个用户都会有它的安全上下文对象,所以把每一个用户的SecurityContext保存到SecurityContextHolder中。

SecurityContextHolder存储SecurityContext的方式根据应用场景不同也有区别:

(1)单机系统,即应用从开启到关闭的整个生命周期只有一个用户在使用。由于整个应用只需要保存一个SecurityContext(安全上下文即可)

(2)多用户系统,比如典型的Web系统,整个生命周期可能同时有多个用户在使用。这时候应用需要保存多个SecurityContext(安全上下文),需要利用ThreadLocal进行保存,每个线程都可以利用ThreadLocal获取其自己的SecurityContext,及安全上下文。ThreadLocal内部会用数组来存储多个对象的。原理是,ThreadLocal会为每个线程开辟一个存储区域,来存储相应的对象。

Authentication:用户信息的表示

在SecurityContextHolder中存储了当前与系统交互的用户的信息。Spring Security使用一个Authentication 对象来表示这些信息。

Authentication 主要包含了:

  • 用户权限集合
  • 用户证书(密码)
  • 细节(Details)
  • Principal(就是这个用户的账户信息)

在自定义登录认证过滤器的时候,记得需要把用户的信息(Authentication )保存到SecurityContextHolder中,以便后续用户的正常使用。比如我在做和Jwt认证的整合的时候,继承OncePerRequestFilter,重写doFilterInternal方法,认证完token之后,就需要把用户的信息存入安全上下文Holder中。

UsernamePasswordAuthenticationToken authenticationToken
=new UsernamePasswordAuthenticationToken(user,null, null);
authenticationToken.setDetails(new WebAuthenticationDetailsSource()
.buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authenticationToken);

关于SecurityContextHolder大概就这样,有一些关于SecurityContextHolder具体的源码的细节可以参考一篇博客:

https://www.cnblogs.com/longfurcat/p/9417912.html

SpringSecurity过滤器原理的更多相关文章

  1. 硬核 | Redis 布隆(Bloom Filter)过滤器原理与实战

    在Redis 缓存击穿(失效).缓存穿透.缓存雪崩怎么解决?中我们说到可以使用布隆过滤器避免「缓存穿透」. 码哥,布隆过滤器还能在哪些场景使用呀? 比如我们使用「码哥跳动」开发的「明日头条」APP 看 ...

  2. Bloom Filter布隆过滤器原理和实现(1)

    引子 <数学之美>介绍布隆过滤器非常经典: 在日常生活中,包括设计计算机软件时,经常要判断一个元素是否在一个集合中.比如: 在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断它 ...

  3. SpringSecurity登录原理(源码级讲解)

    一.简单叙述 首先会进入UsernamePasswordAuthenticationFilter并且设置权限为null和是否授权为false,然后进入ProviderManager查找支持Userna ...

  4. Java过滤器原理方法

    过滤器可以对资源的请求和相应提供过滤功能,配置在web.xml文件中.过滤器可用来实现以下功能1. 权限过滤2. 登陆和检查验证3. 图像转换4. 数据压缩5. 加密6. 令牌验证7. 触发访问资源的 ...

  5. Filter过滤器原理和登录实现

    Filter过滤器API      Servlet过滤器API包含了3个接口,它们都在javax.servlet包中,分别是Filter接口.FilterChain接口和FilterConfig接口. ...

  6. SpringSecurity过滤器顺序

    https://blog.csdn.net/qq_35720307/article/details/97656608 org.springframework.security.config.annot ...

  7. SpringSecurity原理

    一.认证的两种方式的介绍 1. 基于Session的认证方式 在之前的单体架构时代,我们认证成功之后都会将信息存入到Session中,然后响应给客户端的是对应的Session中数据的key,客户端会将 ...

  8. 手撸一个springsecurity,了解一下security原理

    手撸一个springsecurity,了解一下security原理 转载自:www.javaman.cn 手撸一个springsecurity,了解一下security原理 今天手撸一个简易版本的sp ...

  9. 布隆过滤器(Bloom Filter)的原理和实现

    什么情况下需要布隆过滤器? 先来看几个比较常见的例子 字处理软件中,需要检查一个英语单词是否拼写正确 在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上 在网络爬虫里,一个网址是否被访问过 yahoo, ...

随机推荐

  1. FastAPI 学习之路(二十七)安全校验

    你写API接口肯定你是希望是有权限的人才能访问,没有权限的人是不能访问的,那么我们应该如何去处理呢,我们可以用的验证方式有很多,我们这次分享的是用:OAuth2来认证.那么我们看下,需要怎么才能实现呢 ...

  2. 【java】【作业】定义课程信息;继承和组合练习

    问题: 定义课程信息类,包含课程编号.课程名称及学生成绩.编程实现对软件工程专业的某班级的所有课程成绩统计,包括平均成绩.最高成绩.最低成绩,并打印成绩等级分布律. 分析 初分析: 父类(课程信息类) ...

  3. 微软Windows11安卓子系统已支持运行APK 应用(附手把手详细安装攻略)怎么安装安卓/如何安装安卓应用/支持多窗口多任务

    ​​ 10 月 21 日消息,微软博客宣称,Windows 11 上 安卓子系统运行 Android  应用程序的第一个预览版现已提供给美国 Beta 频道的 Windows 内部人员.但现在通过教程 ...

  4. MySQL复习(二)MySQL基本数据类型

    MySQL基本数据类型 常用的字段类型大致可以分为数值类型.字符串类型.日期时间类型三大类 1. 数值类型 数值类型可以分为整型.浮点型.定点型三小类. 1.1 整型 (tiny:极小的, small ...

  5. 第六次Scrum Metting

    日期:2021年5月3日 会议主要内容概述:讨论前后端进度,前端各模块对接以及前后端对接. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 数据模块 ...

  6. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  7. 关于stm32串口必须要学的5个串口以及串口应用和注意事项

    串口是我们常用的一个数据传输接口,STM32F103系列单片机共有5个串口. 其中1-3是通用同步/异步串行接口USART(Universal Synchronous/Asynchronous Rec ...

  8. Unity——射线系统

    Unity射线系统 Demo展示 UI+Physical射线测试: FPS自定义射线测试: UGUI射线工具 实现功能,鼠标点击UI,返回鼠标点击的UI对象: 需要使用到鼠标点击事件-PointerE ...

  9. 好的编程习惯是减少bug最有效的方法

    公司来了几个新手,有时候很简单的一个功能模块都要耗费好几天时间,总是在一些不相关的问题上死耗一整天,搞出莫名其妙的问题,找不到具体原因,总是怀疑编译出问题了,系统出问题了,板子出问题了,搞到快下班了叫 ...

  10. pascals-triangle leetcode C++

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5, Retu ...