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. 自定义cs程序安装界面

    http://www.crifan.com/achieve_fixed_install_path_while_install_software_when_make_msi_installer/ 制作C ...

  2. RabbitMQie消息列队整理

    使用方法过程,这儿只做了windows平台教程 先安装Erlang 编程软件,然后设置环境变量,在安装RabbimMQ ,这儿我下载了一个版本不行,后来换了最新版就好了,以后在使用过程 中如果有问题 ...

  3. 机器学习——正则化方法Dropout

    1 前言 2012年,Dropout的想法被首次提出,受人类繁衍后代时男女各一半基因进行组合产生下一代的启发,论文<Dropout: A Simple Way to Prevent Neural ...

  4. 项目需求分析与建议——NABCD模型

    特点一:旧物再利用N:需求:在我们的校园生活中,会遇到许多自己用不到的东西例如,学过的课本.废置的闲置物品等,这些"废物"往往占据着许多空间却不能够发挥自身的价值,通过我们的校园二 ...

  5. PTA 面向对象程序设计 6-3 面积计算器(函数重载)

    6-3 面积计算器(函数重载) 实现一个面积计算器,它能够计算矩形或长方体的面积. 函数接口定义: int area(int x, int y); int area(int x, int y, int ...

  6. Go学习【02】:理解Gin,搭一个web demo

    Go Gin 框架 说Gin是一个框架,不如说Gin是一个类库或者工具库,其包含了可以组成框架的组件.这样会更好理解一点. 举个 下面的示例代码在这:github 利用Gin组成最基本的框架.说到框架 ...

  7. JDBC-2(CRUD)

    3.PreparedStatement实现CRUD 3.1 操作和访问数据库 数据库连接被用于向数据库服务器发送命令和SQL语句,接受数据库服务器返回的结果.(一个数据库连接就是也给Socket连接) ...

  8. selenium下拉选择框处理

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

  9. 鸿蒙内核源码分析(进程回收篇) | 老父亲如何向老祖宗临终托孤 ? | 百篇博客分析OpenHarmony源码 | v47.01

    百篇博客系列篇.本篇为: v47.xx 鸿蒙内核源码分析(进程回收篇) | 临终前如何向老祖宗托孤 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管 ...

  10. CF1556D-Take a Guess【交互】

    正题 题目链接:https://codeforces.com/contest/1556/problem/D 题目大意 现在有\(n\)个你不知道的数字,你有两种询问操作 询问两个下标的数字的\(and ...