1. Spring Security 简介

  在 Spring 生态系统中,为他的项目增加安全性,你可以借助 Spring Security 库来做到这一点。

  那什么是 Spring Security?

  从本质上讲,Spring Security 实际上只是一堆 servlet 过滤器,可帮助您向Web应用程序添加身份验证授权。还与 Spring Web MVC(或 Spring Boot)之类的框架以及 OAuth2 或SAML 之类的标准很好地集成。并且它会自动生成登录/注销页面,并防御 CSRF 等常见漏洞。

  

  学习 Spring Security 前需要了解三个重要概念:

  1. Authentication(认证)

  2. Authorization(授权)

  3. Servlet Filters(一系列 Servlet 过滤器)

  1)认证

  首先,如果您正在运行典型的(网络)应用程序,则需要你的用户进行身份验证。这意味着您的应用需求,以验证用户是否是谁,他声称自己是,通常与一个用户名和密码检查来完成。

  Authentication 主要构件:

  • SecurityContextHolder:Spring Security在此处存储经过身份验证的人员的详细信息。

  • SecurityContext:SecurityContextHolder 中获取并包含 Authentication 当前经过身份验证的用户的。

  • Authentication:可以是 AuthenticationManager 的输入,以提供用户提供的用于身份验证的凭据或来自 SecurityContext 的当前用户。

  • GrantedAuthority:在身份验证的基础上授予委托人的权限(即角色,作用域等)

  • AuthenticationManager:定义 Spring Security 的过滤器如何执行身份验证的 API。

  • ProviderManager:最常见的实现 AuthenticationManager

  • AuthenticationProvider:ProviderManager 用于执行特定类型的身份验证。

  • 使用 AuthenticationEntryPoint 的请求凭据:用于从客户端请求凭据(即,重定向到登录页面,发送 WWW-Authenticate 响应等)

  • AbstractAuthenticationProcessingFilter: 用于认证的基础 Filter 。这也为高级别的身份验证流程以及各个部分如何协同工作提供了一个好主意。

  认证机制:

  • 用户名和密码:如何使用用户名/密码进行身份验证

  • OAuth 2.0登录:使用 OpenID Connect 和非标准 OAuth 2.0 登录(即 GitHub)登录的 OAuth 2.0

  • SAML 2.0登录SAML 2.0 登录

  • 中央身份验证服务器(CAS):中央身份验证服务器(CAS)支持

  • Remember Me:记住用户过期的会话的功能

  • JAAS认证:使用 JAAS 进行认证

  • OpenID:OpenID 身份验证(请勿与 OpenID Connect 混淆)

  • 预先身份验证方案(Pre-Authentication Scenarios):使用诸如 SiteMinder 或 Java EE 安全性之类的外部机制进行身份验证,但仍使用 Spring Security 进行授权和防范常见漏洞利用。

  • X509验证:X509 验证

2. Authentication 主要构件介绍

  ① SecurityContextHolder

   Spring Security 身份验证模型的核心是 SecurityContextHolder。它包含 SecurityContext

  SecurityContextHolder 用于存储通过身份验证的人员的详细信息。

   如下代码所示,指示用户已通过身份验证的最简单方法是直接设置 SecurityContextHolder :

1   SecurityContext context = SecurityContextHolder.createEmptyContext();
2   Authentication authentication =
3   new TestingAuthenticationToken("username", "password", "ROLE_USER");
4   context.setAuthentication(authentication);
5
6   SecurityContextHolder.setContext(context);

  如果你希望获取有关已认证主体的信息,可以通过以下方式访问 SecurityContextHolder 来获得。

1     SecurityContext context = SecurityContextHolder.getContext();
2 Authentication authentication = context.getAuthentication();
3 String username = authentication.getName();
4 Object principal = authentication.getPrincipal();
5 Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); 

  ② SecurityContext 安全上下文

  在 SecurityContextHolder 中所得 SecurityContext 中。该 SecurityContext 包含认证对象。

  ③ Authentication

  它们 Authentication 在 Spring Security 中有两个主要目的:

  • AuthenticationManager 用于提供用户已提供身份验证的凭据的输入。在这种情况下使用时, isAuthenticated() 返回 false。

  • 代表当前经过身份验证的用户。当前 Authentication 可以从 SecurityContext 获得。

  该 Authentication 包含:

  • principal:识别用户。使用用户名/密码进行身份验证时,这通常是的实例  UserDetails 。

  • credentials:通常是密码。在许多情况下,将在验证用户身份后清除此内容,以确保它不会泄漏。

  • authorities:在 GrantedAuthority 是授予用户的高级别权限。比如说角色或范围。

  ④ GrantedAuthority 授予的权限

  GrantedAuthority 是用户将被授予的高级别权限。比如说角色或范围。

  GrantedAuthority 可以从该 Authentication.getAuthorities() 方法获得。此方法提供了一个 GrantedAuthority 集合对象。GrantedAuthority 是授予某个主体的权限。此类权限通常是“角色”,例如 ROLE_ADMINISTRATOR 或 ROLE_HR_SUPERVISOR 。稍后将这些角色配置为 Web授权,方法授权和域对象授权。Spring Security 的其他部分能够解释这些权限,并希望它们存在。使用基于用户名/密码的身份验证时GrantedAuthority,通常会由加载 UserDetailsService 。

  通常,GrantedAuthority 对象是应用程序范围的权限。它们不特定于给定的域对象。因此,您不可能 GrantedAuthority 代表 Employee 54号对象的权限,因为如果有成千上万个这样的权限,这将很快用完内存(或者至少导致应用程序花费很长时间来完成验证用户身份)。当然,Spring Security是专门为满足这一通用要求而设计的,但你可以为此目的使用项目的域对象安全性功能。

  

  ⑤ AuthenticationManager 认证管理器

   AuthenticationManager 定义 Spring Security 的过滤器是如何执行身份验证的 API 。然后再由调用 AuthenticationManager 的控制器(即 Spring Security 的 Filters)在SecurityContextHolder 上设置返回的Authentication。如果您不与Spring Security的过滤器集成,则可以直接设置 SecurityContextHolder,并且不需要使用 AuthenticationManager。

尽管的实现 AuthenticationManager 可以是任何对象,但最常见的实现是 ProviderManager

  ⑥ ProviderManager 

  ProviderManager 是 AuthenticationManager 的最常见实现。ProviderManager 委托给 AuthenticationProvider 列表。 每个 AuthenticationProvider 都有机会指示认证应该成功,失败,或者表明它不能做出决定并允许下游 AuthenticationProvider 进行决定。 如果没有配置的 AuthenticationProviders 可以进行身份验证,则身份验证将失败,并显示ProviderNotFoundException,这是一个特殊的 AuthenticationException,它指示未配置 ProviderManager 支持传递给它的身份验证类型。

 

  实际上,每个 AuthenticationProvider 都知道如何执行特定类型的身份验证。 例如,一个 AuthenticationProvider 可能能够验证用户名/密码,而另一个可能能够验证 SAML 断言。 这允许每个 AuthenticationProvider 进行非常特定类型的身份验证,同时支持多种类型的身份验证,并且仅公开一个单例 AuthenticationManager bean。

  ProviderManager 还允许配置可选的父类 AuthenticationManager,如果没有 AuthenticationProvider 可以执行身份验证,请咨询该父对象。 父级可以是任何类型的AuthenticationManager,但通常是 ProviderManager的实例。

  实际上,多个 ProviderManager 实例可能共享同一个父类 AuthenticationManager。 在存在多个具有相同身份验证(共享的父类 AuthenticationManager)但又具有不同身份验证机制(不同 ProviderManager 实例)的多个 SecurityFilterChain 实例的情况下,这种情况有些常见。

  默认情况下,ProviderManager 会尝试清除身份验证对象中所有敏感的凭据信息,这些信息将由成功的身份验证请求返回。 这样可以防止密码之类的信息在 HttpSession 中的保留时间超过所需的时间。

  例如,在使用用户对象的缓存来提高无状态应用程序的性能时,这可能会导致问题。 如果身份验证包含对缓存中某个对象(例如 UserDetails 实例)的引用,并且已删除其凭据,则将无法再对缓存的值进行身份验证。 如果使用缓存,则需要考虑到这一点。 一个明显的解决方案是首先在缓存实现中或在创建返回的 Authentication 对象的 AuthenticationProvider 中创建对象的副本。 或者,你可以在 ProviderManager 上禁用 deleteCredentialsAfterAuthentication 属性。

  ⑦ AuthenticationProvider

  可以将多个 AuthenticationProvider 注入 ProviderManager。 每个 AuthenticationProvider 执行特定类型的身份验证。 例如,DaoAuthenticationProvider 支持基于用户名/密码的身份验证,而 JwtAuthenticationProvider 支持对JWT令牌的身份验证。AuthenticationEntryPoint

  ⑧ 使用 AuthenticationEntryPoint 的请求凭据

  AuthenticationEntryPoint 用于发送请求凭据响应,以回应客户端 HTTP 认证。有时,客户端会主动包含凭据(例如用户名/密码)以请求资源。 在这些情况下,Spring Security 不需要提供 HTTP 响应来从客户端请求凭据,因为它们已经包含在内。

  在其他情况下,客户端将对未经授权访问的资源发出未经身份验证的请求。 在这种情况下,AuthenticationEntryPoint 的实现用于从客户端请求凭据。 AuthenticationEntryPoint 实现可能会执行重定向到登录页面,使用 WWW-Authenticate 标头进行响应等。

  ⑨ AbstractAuthenticationProcessingFilter

  AbstractAuthenticationProcessingFilter 用作验证用户凭据的基本过滤器。 在对凭证进行身份验证之前,Spring Security 通常使用 AuthenticationEntryPoint 请求凭证。

  接下来,AbstractAuthenticationProcessingFilter 可以对提交给它的任何身份验证请求进行身份验证。

  1. 当用户提交其凭据时,AbstractAuthenticationProcessingFilter 从要验证的 HttpServletRequest 创建一个 Authentication。创建的身份验证类型取决于 AbstractAuthenticationProcessingFilter 的子类。例如,UsernamePasswordAuthenticationFilter 根据在 HttpServletRequest 中提交的用户名和密码来创建UsernamePasswordAuthenticationToken。

  2. 接下来,将身份验证传递到AuthenticationManager进行身份验证。

  3. 如果身份验证失败,则失败事件有:

    已清除 SecurityContextHolder。

    RememberMeServices.loginFail 被调用。如果 RememberMe 未配置,则为空。

    AuthenticationFailureHandler 被调用。

  4. 如果身份验证成功,则成功事件有:

    SessionAuthenticationStrategy 会通知有新的登录。

    身份验证是在SecurityContextHolder上设置的。 之后,SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession中。

    RememberMeServices.loginSuccess 被调用。 如果 RememberMe 未配置,则为空。

    ApplicationEventPublisher 发布一个 InteractiveAuthenticationSuccessEvent。

  ⑩ Username/Password Authentication

  验证用户身份的最常见方法之一是验证用户名和密码。这样,Spring Security 为使用用户名和密码进行身份验证提供了全面的支持。

  Spring Security 提供了以下内置机制,用于从 HttpServletRequest 中读取用户名和密码:

  • Form Login(表单登入)

  • Basic Authentication(基本认证)

  • Digest Authentication(摘要式身份验证)

  用于读取用户名和密码的每种受支持的机制都可以利用任何受支持的存储机制

  • 具有内存内认证的简单存储(In-Memory Authentication)
  • 具有 JDBC 身份验证的关系数据库(JDBC Authentication)
  • 使用 UserDetailsService 的自定义数据存储(use UserDetails)
  • 具有 LDAP 认证的 LDAP 存储(LDAP Authentication)

  ⑪ Session Management

  与 HTTP 会话相关的功能由 SessionManagementFilter 和 SessionAuthenticationStrategy 接口的组合来处理,过滤器委托该接口。 典型的用法包括防止会话固定保护攻击,检测会话超时以及限制已认证用户可以同时打开多少个会话。其功能有:

  • 检测超时

  • 并发会话控制

  • 会话固定攻击防护

  • SessionManagementFilter

  • SessionAuthenticationStrategy

  • 并发控制

  ⑫ Remember-Me 认证

  “记住我”或“永久登录”身份验证是指能够记住会话之间的主体身份的网站。 通常,这是通过向浏览器发送一个 cookie 来实现的,该 cookie 在以后的会话中被检测到并导致自动登录。 Spring Security 提供了进行这些操作所需的钩子,并具有两个具体的“记住我”实现。 一种使用散列来保留基于 cookie 的令牌的安全性,另一种使用数据库或其他持久性存储机制来存储生成的令牌。这两种实现都需要 UserDetailsService。

  ⑬ 注销处理

  使用 WebSecurityConfigurerAdapter 时,将自动应用注销功能。 默认是访问 URL / logout 将通过以下方式注销用户:

  • 使 HTTP 会话无效

  • 清理配置的所有 RememberMe 身份验证

  • 清除 SecurityContextHolder

  • 重定向到 /login?logout

  ⑭ 认证事件

  对于成功或失败的每个身份验证,分别触发 AuthenticationSuccessEvent 或 AuthenticationFailureEvent。

  若要侦听这些事件,必须首先发布 AuthenticationEventPublisher。 Spring Security 的 DefaultAuthenticationEventPublisher 可能会很好:

1 @Bean
2 public AuthenticationEventPublisher authenticationEventPublisher
3 (ApplicationEventPublisher applicationEventPublisher) {
4 return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
5 }

  然后,你可以使用 Spring 的 @EventListener 支持:

 1 @Component
2 public class AuthenticationEvents {
3 @EventListener
4 public void onSuccess(AuthenticationSuccessEvent success) {
5 // ...
6 }
7
8 @EventListener
9 public void onFailure(AuthenticationFailureEvent failures) {
10 // ...
11 }
12 }

  尽管与 AuthenticationSuccessHandler 和 AuthenticationFailureHandler 相似,但它们的优点是可以独立于Servlet API使用。

  (etc.)

主要译自:Spring Security官方文档

Spring Security:Authentication 认证(一)的更多相关文章

  1. Spring boot +Spring Security + Thymeleaf 认证失败返回错误信息

    [Please make sure to select the branch corresponding to the version of Thymeleaf you are using] Stat ...

  2. 最简单易懂的Spring Security 身份认证流程讲解

    最简单易懂的Spring Security 身份认证流程讲解 导言 相信大伙对Spring Security这个框架又爱又恨,爱它的强大,恨它的繁琐,其实这是一个误区,Spring Security确 ...

  3. Spring Cloud实战 | 第九篇:Spring Cloud整合Spring Security OAuth2认证服务器统一认证自定义异常处理

    本文完整代码下载点击 一. 前言 相信了解过我或者看过我之前的系列文章应该多少知道点我写这些文章包括创建 有来商城youlai-mall 这个项目的目的,想给那些真的想提升自己或者迷茫的人(包括自己- ...

  4. Spring Security 接口认证鉴权入门实践指南

    目录 前言 SpringBoot 示例 SpringBoot pom.xml SpringBoot application.yml SpringBoot IndexController SpringB ...

  5. Spring Security 入门(1-5)Spring Security - 匿名认证

    匿名认证 对于匿名访问的用户,Spring Security 支持为其建立一个匿名的 AnonymousAuthenticationToken 存放在 SecurityContextHolder 中, ...

  6. 学习Spring Boot:(二十八)Spring Security 权限认证

    前言 主要实现 Spring Security 的安全认证,结合 RESTful API 的风格,使用无状态的环境. 主要实现是通过请求的 URL ,通过过滤器来做不同的授权策略操作,为该请求提供某个 ...

  7. 学习Spring Security OAuth认证(一)-授权码模式

    一.环境 spring boot+spring security+idea+maven+mybatis 主要是spring security 二.依赖 <dependency> <g ...

  8. Spring Security 安全认证

    Spring Boot 使用 Mybatis 依赖 <dependency> <groupId>org.mybatis.spring.boot</groupId> ...

  9. SpringBoot Spring Security 核心组件 认证流程 用户权限信息获取详细讲解

    前言 Spring Security 是一个安全框架, 可以简单地认为 Spring Security 是放在用户和 Spring 应用之间的一个安全屏障, 每一个 web 请求都先要经过 Sprin ...

  10. Spring Security 匿名认证

    1.项目截图: 2.匿名认证配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=& ...

随机推荐

  1. umi request 请求资源库详解

    umi-request: 网络请求库,基于fetch封装,兼具fetch 和 axios 的所有特点,具有缓存,超时,字符编码处理,错误处理等常用功能. 1 支持url 参数自动序列化. 2 post ...

  2. 性能再提升70%?大咖前瞻带你揭开.NET6的神秘面纱!

    本月初微软官宣.NET 6 的RC1即将在11月正式发布,这意味着.NET6正式版跟我们见面的时间又近了一步.在之前的.NET6预览版本中,微软加入了大量新功能特性,而在最终版本中将不再额外加入新的内 ...

  3. PHP中的PDO操作学习(二)预处理语句及事务

    今天这篇文章,我们来简单的学习一下 PDO 中的预处理语句以及事务的使用,它们都是在 PDO 对象下的操作,而且并不复杂,简单的应用都能很容易地实现.只不过大部分情况下,大家都在使用框架,手写的机会非 ...

  4. mysql5.7当两个字段名类似,查询时会出错

    excepInfo: select id,describe from iwebshop_student_problem where id=256 order by id desc -- You hav ...

  5. xmind使用技巧

    xmind看似每个人都会使用,但是掌握一些小技巧,能够有效提升工作效率. 多行复制粘贴 在xmind中选中多行,复制然后可以直接粘贴到excel.word当中. 在excel.word选中多行,复制然 ...

  6. spl_autoload_register 实现自动加载

    spl_autoload_register 注册给定的函数作为 __autoload 的实现 bool spl_autoload_register ([ callable $autoload_func ...

  7. selenium下拉选择框处理

    HTML: (一)通过xpath层级标签定位 driver.find_element_by_xpath(".//*[@id='Resolution']/option[2]").cl ...

  8. CF700E-Cool Slogans【SAM,线段树合并,dp】

    正题 题目链接:https://www.luogu.com.cn/problem/CF700E 题目大意 给出一个字符串\(S\),求一个最大的\(k\)使得存在\(k\)个字符串其中\(s_1\)是 ...

  9. P3971-[TJOI2014]Alice and Bob【贪心】

    正题 题目链接:https://www.luogu.com.cn/problem/P3971 题目大意 一个\(1\sim n\)的一个排列,设\(a_i\)表示以\(i\)结尾的最长上升子序列长度, ...

  10. P4321-随机漫游【状压dp,数学期望,高斯消元】

    正题 题目链接:https://www.luogu.com.cn/problem/P4321 题目大意 给出\(n\)个点\(m\)条边的一张无向图,\(q\)次询问. 每次询问给出一个点集和一个起点 ...