SpringSecurity - 基于 Servlet 的应用程序

SpringSecurity 学习指南大全
开源 Spring Security 前后端分离 - 后端示例

文章目录

基于 Servlet 的应用程序

Spring Security 使用标准的 Servlet Filter(过滤器) 来与 Servlet 容器进行集成。也就是说它可以与运行在 Servlet 容器中的任何应用程序一起工作。更具体地说,您可以在基于 Servlet 的应用程序中不使用 Spring 来整合 Spring Security。

新手入门

本节将介绍如何在 SpringBoot 中快速使用 SpringSecurity。

环境准备
  • JDK 1.8+
  • Maven
引入依赖
  1. 创建一个基础 SpringBoot 的 Web 项目,添加基础依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- Spring Boot 父项目-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>

    <groupId>org.example</groupId>
    <artifactId>securityDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Spring 监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>

        <!-- Spring Boot开发者工具 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

除了 Web 其它可以按需引入即可。

  1. 添加 SpringSecurity 的启动器:
<!-- Spring 安全框架 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  1. 编写 Hello 接口和 SpringBoot 启动类
@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        return "Hello Security!";
    }

}

到此 SpringBoot 整合 SpringSecurity 的基本完成。当然我们后续还需要自定义配置。

启动项目

输出日志:

2022-06-12 12:02:38.499  WARN 6952 --- [  restartedMain] .s.s.UserDetailsServiceAutoConfiguration : 

Using generated security password: aa45a28b-214b-4bdb-80e2-35183dfa2e49

This generated password is for development use only. Your security configuration must be updated before running your application in production.

默认 SpringSecurity 会提供一个 user 用户,并随即生成密码输出到控制台。并且默认会提供一个登录页面。

我们访问 http://localhost:8080/hello 接口,可以发现已经被 Security 拦截了,被重定向到 http://localhost:8080/login SpringSecurity 默认提供的登录页面。

在这里插入图片描述

使用 user 和随机密码进行登录,我们就可以访问我们的 hello 接口了。我们的 SpringBoot 应用已经被 Security 监管起来了。

基础入门就是这么简单,那么这其中到底做了什么呢,一切都可以从查看 SpringBoot 的自动配置开始。

SpringBoot 的自动配置

接下来我们需要了解 SpringBoot 都干了哪些事情。

  • 启用了 Spring Security 的默认配置,此配置将 servlet Filter 创建为名为 springSecurityFilterChain 的 bean。 此 bean 负责应用程序中的所有安全(如保护应用程序 URL、验证提交的用户名和密码、重定向到登录表单等)。
  • 使用用户名为 user 和随机生成的密码创建 UserDetailsService bean,并将其记录到控制台。
  • 使用 Servlet 容器为每个请求注册一个 bean 名为 springSecurityFilterChain 的过滤器。

SpringBoot 的自动配置不多,但实现了许多功能,功能如下:

  • 经过身份验证的用户才能与应用程序进行任何交互
  • 生成默认登录表单
  • 提供名为 user 的默认用户,来进行基于表单的身份验证
  • 使用 BCrypt 来进行密码加密
  • 提供用户退出接口
  • CSRF 攻击预防
  • Session 固定保护
  • 提供 Security Header 集成
  • 与 Servlet API 方法集成

架构

本节讨论 Spring Security 在基于 Servlet 的应用程序中的架构理论。并且在后续的身份验证、授权、防止漏洞利用文章中实现了此架构理论。

过滤器回顾

Spring Security 实现 Servlet 支持是基于 Servlet 的 Filters,所以我们先回顾一下 Filters 的作用。 下图展示了单个 HTTP 请求到达处理程序典型的执行流程。

在这里插入图片描述

客户端向应用程序发送一个请求,容器创建一个 FilterChain,其中包含 Filter 和 Servlet,它们根据请求的 URI 路径处理HttpServletRequest。在 Spring MVC 应用程序中,Servlet 是 DispatcherServlet 的一个实例。一个 Servlet 最多可以处理一个HttpServletRequest 和 HttpServletResponse。但可以使用多个 Filter 来:

  • 防止下游 Filter 或 Servlet 被调用。在这种情况下,Filter 通常会写入 HttpServletResponse。
  • 修改下游 Filter 和 Servlet 使用的 HttpServletRequest 或 HttpServletResponse。

Filter 的能力来自传递给它的 FilterChain(过滤器链)。

过滤器链使用示例:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// 在应用程序的其余部分之前做一些事情
    chain.doFilter(request, response); // 调用应用程序的其余部分
    // 在应用程序的其余部分之后做一些事情
}

因为 Filter 只影响下游的 Filter 和 Servlet,所以调用每个 Filter 的顺序非常重要。

DelegatingFilterProxy:委派过滤器代理

Spring 提供了一个名为 DelegatingFilterProxy 的过滤器实现,允许在 Servlet 容器的生命周期和 Spring 的 ApplicationContext 之间建立桥梁进行沟通。Servlet 容器允许使用自己的标准注册过滤器,但是它不知道 Spring 定义的 Beans。

DelegatingFilterProxy 可以通过标准的 Servlet 容器机制注册,但是将所有工作委托给实现 Filter 的 Spring Filter Bean。

下面这张图片展示了 DelegatingFilterProxy 如何加入Spring Filter Bean 和 FilterChain。

在这里插入图片描述

DelegatingFilterProxy 可以从 ApplicationContext 中查找 Bean Filter0,然后调用 Bean Filter0。DelegatingFilterProxy 的伪代码如下所示。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
	// 延迟获取注册为Spring Bean的过滤器
	// delegate 是 Bean Filter0 的实例
	Filter delegate = getFilterBean(someBeanName);
	// delegate 将工作委托给 Spring Bean
	delegate.doFilter(request, response);
}

DelegatingFilterProxy 的另一个好处是它允许延迟查找 Filter bean 实例。这很重要,因为容器需要在容器启动之前注册 Filter 实例。但是,Spring 通常使用 ContextLoaderListener 来加载 Spring Bean,直到需要注册 Filter 实例之后才会完成。

FilterChainProxy:过滤器链代理

Spring Security 的 Servlet 支持包含在 FilterChainProxy 中。FilterChainProxy 是 Spring Security 提供的一个特殊 Filter,它允许通过SecurityFilterChain 委托给多个 Filter 实例。因为 FilterChainProxy 是一个 Bean,所以它通常被包装在 DelegatingFilterProxy 中。

在这里插入图片描述

SecurityFilterChain:Security 过滤器链

FilterChainProxy 通过使用 SecurityFilterChain 来确定应该为此请求调用哪些 Spring Security Filters。

在这里插入图片描述

SecurityFilterChain 中的 Security Filters 通常是Beans,但它们是用 FilterChainProxy 而不是 DelegatingFilterProxy 注册的。FilterChainProxy 提供了许多直接向 Servlet 容器或 DelegatingFilterProxy 注册的优点。首先,它为 Spring Security 的所有 Servlet 支持提供了一个起点。因此,如果您试图对 Spring Security 的 Servlet 支持进行故障排除,在 FilterChainProxy 中添加一个调试点是一个很好的起点。

其次,由于 FilterChainProxy 是 Spring Security 使用的核心,它可以执行不被视为可选的任务。例如,它清除 SecurityContext 以避免内存泄漏。它还应用 Spring Security 的 HttpFirewall 来保护应用程序免受某些类型的攻击。

此外,在确定何时应该调用 SecurityFilterChain 时,它提供了更多的灵活性。在 Servlet 容器中,Filter 仅基于 URL 被调用。但是,FilterChainProxy 可以通过利用 RequestMatcher 接口,基于 HttpServletRequest 中的任何内容来确定调用。

事实上,FilterChainProxy 可以用于确定应该使用哪个 SecurityFilterChain。这允许为应用程序的不同部分提供完全独立的配置。
在这里插入图片描述

在多个 SecurityFilterChain 中,FilterChainProxy 决定应该使用哪个 SecurityFilterChain。但只会调用第一个匹配的 SecurityFilterChain。如果请求 /api/messages/ 的 URL,它将首先匹配 SecurityFilterChain 0/api/**,因此即使它也匹配 SecurityFilterChain n,但也只会调用 SecurityFilterChain 0

如果请求 /messages/ 的URL,它将与 SecurityFilterChain 0/api/** 模式不匹配,因此 FilterChainProxy 将继续尝试每个 SecurityFilterChain。假设没有其它的与其匹配,则将调用匹配 SecurityFilterChain n 的 SecurityFilterChain 实例。

请注意,SecurityFilterChain0 只配置了三个 security Filter 实例。但是,SecurityFilterChain n 配置了四个安全筛选器。请务必注意,每个 SecurityFilterChain 都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望 Spring Security 忽略某些请求,SecurityFilterChain 可能没有安全过滤器。

Security Filters:安全过滤器

Security Filters 通过 SecurityFilterChain API 插入到 FilterChainProxy 中。Filter 的顺序很重要。

以下是 Spring Security Filter 排序的完整列表:

  • ForceEagerSessionCreationFilter
  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter
处理 Security 异常

ExceptionTranslationFilter 允许将 AccessDeniedException 和 AuthenticationException 转换为 HTTP 响应。

ExceptionTranslationFilter 作为 Security Filters 之一插入到 FilterChainProxy 中。

在这里插入图片描述
在这里插入图片描述

  1. 首先,ExceptionTranslationFilter 调用 FilterChain.doFilter(request,response) 来调用应用程序的其余部分。

  2. 如果用户未通过身份验证或者是 AuthenticationException,则开始身份验证。

    1. SecurityContextHolder 被清除
    2. HttpServletRequest 保存在 RequestCache 中。当用户成功通过身份验证时,RequestCache 用于重放原始请求
    3. AuthenticationEntryPoint 用于从客户端请求凭据。 例如,它可能重定向到登录页面或发送 WWW-Authenticate header。
  3. 否则,如果是 AccessDeniedException,则拒绝访问。调用 AccessDeniedHandler 来处理拒绝访问。

如果应用程序不抛出 AccessDeniedException 或 AuthenticationException,则 ExceptionTranslationFilter 不做任何事情。

ExceptionTranslationFilter 的伪代码如下所示:

try {
	filterChain.doFilter(request, response); // 1 调用后面程序可能会抛出异常
} catch (AccessDeniedException | AuthenticationException ex) {	// 捕获异常
	if (!authenticated || ex instanceof AuthenticationException) {
		startAuthentication(); // 2	开启身份验证
	} else {
		accessDenied(); // 3 拒绝访问
	}
}
  1. 回顾一下过滤器,您会记得调用 FilterChain.doFilter(request,response) 相当于调用应用程序的其余部分。这意味着如果应用程序的另一部分(即 FilterSecurityInterceptor 或 method security)抛出 AuthenticationException 或 AccessDeniedException,它将在此被捕获并处理。
  2. 如果用户未通过身份验证或者是 AuthenticationException,则开启身份验证。
  3. 否则,拒绝访问

认证

Spring Security 为认证提供了全面的支持。我们从讨论整体 Servlet 认证架构开始。正如您所预料的,这一部分更抽象地描述了架构,而没有过多地讨论它如何应用于具体的流程。

Servlet 认证架构

本节讨论扩展了 Servlet Security 架构,描述在 Servlet 认证中使用的 Spring Security 的主要架构组件。如果您需要具体的流程来解释这些部分是如何组合在一起的,请查看具体身份验证机制。

  • SecurityContextHolder:SecurityContextHolder 用于存储 Spring Security 经过身份验证的人的详细信息。
  • SecurityContext:从 SecurityContextHolder 获取,包含当前已通过身份验证的用户的身份验证。
  • Authentication:可以是 AuthenticationManager 的输入,以提供用户提供的凭据以进行身份验证,也可以是 SecurityContext 中的当前用户。
  • GrantedAuthority:在身份验证上授予主体的权限(即角色、范围等)
  • AuthenticationManager:定义 Spring Security 的 Filter 如何执行身份验证的 API。
  • ProviderManager:AuthenticationManager 最常见的实现。
  • AuthenticationProvider:ProviderManager 使用它来执行特定类型的身份验证。
  • 使用 AuthenticationEntryPoint 请求凭据:用于从客户端请求凭据(即重定向到登录页面、发送 WWW-Authenticate 响应等)
  • AbstractAuthenticationProcessingFilter:用于身份验证的基本 Filter。此类很好地说明了身份验证的高级流程以及各个部分如何协同工作。
SecurityContextHolder:安全上下文持有者

Spring Security 认证模型的核心是 SecurityContextHolder。它包含 SecurityContext。

在这里插入图片描述

SecurityContextHolder 是 Spring Security 存储经过身份验证的人的详细信息的地方。Spring Security 不关心如何填充SecurityContextHolder。如果它包含一个值,那么它将被用作当前经过身份验证的用户。

指示用户已通过身份验证的最简单方法是直接设置 SecurityContextHolder。

SecurityContext context = SecurityContextHolder.createEmptyContext(); // 1
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER"); // 2
context.setAuthentication(authentication);

SecurityContextHolder.setContext(context);  // 3
  1. 我们首先创建一个空的 SecurityContext。 重要的是创建一个新的 SecurityContext 实例而不是使用 SecurityContextHolder.getContext().setAuthentication(authentication) 以避免跨多个线程的竞争条件。
  2. 接下来我们创建一个新的 Authentication 对象。 Spring Security 不关心 SecurityContext 上设置了哪种类型的身份验证实现。 这里我们使用 TestingAuthenticationToken 因为它非常简单。 更常见的生产场景是 UsernamePasswordAuthenticationToken(userDetails, password, authority)。
  3. 最后,我们在 SecurityContextHolder 上设置 SecurityContext。 Spring Security 将使用此信息进行授权。

如果您希望获取有关经过身份验证的主体的信息,可以通过访问 SecurityContextHolder 来实现。

SecurityContext context = SecurityContextHolder.getContext(); // 获得 SecurityContext
Authentication authentication = context.getAuthentication(); // 获得当前认证对象
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();	// 获得认证对象的权限集合

默认情况下,SecurityContextHolder 使用 ThreadLocal 来存储这些详细信息,这意味着 SecurityContext 始终可用于同一线程中的方法,即使 SecurityContext 没有明确地作为参数传递给这些方法。 如果在处理当前主体的请求后注意清除线程,那么以这种方式使用 ThreadLocal 是非常安全的。 Spring Security 的 FilterChainProxy 确保 SecurityContext 总是被清除。

有些应用程序并不完全适合使用 ThreadLocal,因为它们使用线程的特定方式。 例如,Swing 客户端可能希望 Java 虚拟机中的所有线程使用相同的安全上下文。 SecurityContextHolder 可以在启动时配置一个策略,以指定您希望如何存储上下文。对于独立应用程序,您将使用 SecurityContextHolder.MODE_GLOBAL 策略。 其他应用程序可能希望安全线程产生的线程也采用相同的安全身份。这是通过使用 SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 来实现的。 您可以通过两种方式从默认的 SecurityContextHolder.MODE_THREADLOCAL 更改模式。 第一个是设置系统属性,第二个是调用 SecurityContextHolder 的静态方法。 大多数应用程序不需要更改默认设置,但如果您这样做,请查看 Javadoc for SecurityContextHolder 以了解更多信息。

SecurityContext:安全上下文

SecurityContext 是从 SecurityContextHolder 获取的。SecurityContext 包含身份验证对象。

Authentication:认证对象

在 Spring Security 中,身份验证有两个主要目的:

  • AuthenticationManager 的输入,用于提供用户提供的身份验证凭据。 在这种情况下使用时,isAuthenticated() 返回 false。
  • 表示当前经过身份验证的用户。 当前的 Authentication 可以从 SecurityContext 中获取。

Authentication 包含以下属性:

  • principal:标识用户。 当使用用户名/密码进行身份验证时,这通常是 UserDetails 的一个实例。
  • credentials:通常是密码。 在许多情况下,这将在用户通过身份验证后被清除,以确保它不被泄露。
  • authorities:GrantedAuthoritys 是授予用户的高级权限。 示例角色或范围。
GrantedAuthority:授予权限

GrantedAuthoritys 是授予用户的高级权限。 示例角色或范围。

GrantedAuthoritys 可以从 Authentication.getAuthorities() 方法中获得。此方法提供 GrantedAuthority 对象的集合。毫不奇怪,GrantedAuthority 是授予委托人的权限。此类权限通常是“角色”,例如 ROLE_ADMINISTRATOR 或 ROLE_HR_SUPERVISOR。这些角色稍后将被配置用于 web 授权、方法授权和 domain(域)对象授权。Spring Security 的其他部分能够解释这些权限,并期望它们存在。 当使用基于用户名/密码的身份验证时,GrantedAuthoritys 通常由 UserDetailsService 加载。

通常,GrantedAuthority 对象是应用程序范围的权限。它们并不特定于给定的 domain(域)对象。因此,您不太可能有一个GrantedAuthority 来表示对编号为 54 的 Employee 对象的权限,因为如果有数千个这样的权限,您会很快耗尽内存(或者,至少会导致应用程序花很长时间来验证一个用户)。当然,Spring Security 是专门为处理这种常见需求而设计的,但您应该为此目的使用项目的 domain(域) 对象安全功能。

AuthenticationManager:认证管理器

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

虽然 AuthenticationManager 的实现可以是任何东西,但最常见的实现是 ProviderManager。

ProviderManager:提供者管理器

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

在这里插入图片描述

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

ProviderManager 还允许配置一个可选的父 AuthenticationManager,在没有 AuthenticationProvider 可以执行身份验证的情况下进行咨询。父级可以是任何类型的 AuthenticationManager,但它通常是 ProviderManager 的一个实例。

在这里插入图片描述

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

在这里插入图片描述

默认情况下,ProviderManager 将尝试从成功的身份验证请求返回的 Authentication 对象中清除任何敏感的凭据信息。这可以防止诸如密码之类的信息在 HttpSession 中保留的时间超过必要的时间。

当您使用用户对象的缓存时,这可能会导致问题,例如,为了提高无状态应用程序的性能。如果 Authentication 包含对缓存中的对象(例如 UserDetails 实例)的引用,并且已删除其凭据,则将不再可能针对缓存的值进行身份验证。如果您使用缓存,则需要考虑到这一点。一个明显的解决方案是首先在缓存实现中或在创建返回的 Authentication 对象的 AuthenticationProvider 中制作对象的副本。或者,您可以禁用 ProviderManager 上的 eraseCredentialsAfterAuthentication 属性。有关更多信息,请参阅 Javadoc

AuthenticationProvider:认证提供者

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

使用 AuthenticationEntryPoint 请求凭据

AuthenticationEntryPoint 用于发送从客户端请求凭据的 HTTP 响应。

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

也就是说如果客户端的请求没有经过认证,会响应客户端需要认证信息,常使用在未认证处理。

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

AbstractAuthenticationProcessingFilter:抽象身份验证处理过滤器

凭据可以是用户登录信息或者token等等,代表用户有效证明的数据

AbstractAuthenticationProcessingFilter 是验证用户凭据的基本过滤器。在可以对凭据进行身份验证之前,Spring Security 通常使用 AuthenticationEntryPoint 来响应用户访问请求需要凭据。

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

在这里插入图片描述
在这里插入图片描述

  1. 当用户提交他们的凭据时, AbstractAuthenticationProcessingFilter 从 HttpServletRequest 创建一个 Authentication 以进行身份验证。创建的 Authentication 类型取决于 AbstractAuthenticationProcessingFilter 的子类。例如,UsernamePasswordAuthenticationFilter 根据在 HttpServletRequest 中提交的用户名和密码创建 UsernamePasswordAuthenticationToken。
  2. 接下来,将 Authentication 传递给 AuthenticationManager 进行身份验证。
  3. 如果认证失败,则失败
    1. SecurityContextHolder 已被清除。
    2. 调用 RememberMeServices.loginFail。 如果记住我没有配置,这是一个空操作。
    3. AuthenticationFailureHandler 被调用。
  4. 如果认证成功,则成功。
    1. SessionAuthenticationStrategy 收到新登录通知。
    2. Authentication 在 SecurityContextHolder 上设置。 稍后 SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession。
    3. 调用 RememberMeServices.loginSuccess。 如果记住我没有配置,这是一个空操作。
    4. ApplicationEventPublisher 发布一个 InteractiveAuthenticationSuccessEvent。
    5. AuthenticationSuccessHandler 被调用。
用户名 / 密码验证

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

读取用户名和密码

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

表单登录

Spring Security 支持通过 html 表单提供用户名和密码。本节详细介绍了基于表单的身份验证在 Spring Security 中是如何工作的。

让我们看看基于表单的登录在 Spring Security 中是如何工作的。首先,我们看到用户如何被重定向到登录表单。

在这里插入图片描述

该图基于我们的 SecurityFilterChain 过滤器链。

  • 首先,用户向未授权的资源 /private 资源发出未经身份验证的请求。
  • Spring Security 的 FilterSecurityInterceptor 通过抛出 AccessDeniedException 来表示未经身份验证的请求被拒绝。
  • 由于用户未经过身份验证,ExceptionTranslationFilter 会启动开始身份验证,并使用配置的 AuthenticationEntryPoint 发送重定向到登录页面。在大多数情况下,AuthenticationEntryPoint 是 LoginUrlAuthenticationEntryPoint 的一个实例。
  • 然后,浏览器将请求它被重定向到的登录页面。
  • 用户可以通过登录页面来进行认证

提交用户名和密码后,UsernamePasswordAuthenticationFilter 将对用户名和密码进行身份验证。UsernamePasswordAuthenticationFilter 继承至 AbstractAuthenticationProcessingFilter,执行流程请看下面这张图:

在这里插入图片描述
在这里插入图片描述

该图基于 SecurityFilterChain 过滤器链:

  1. 当我们进行登录时,UsernamePasswordAuthenticationFilter 会创建一个 UsernamePasswordAuthenticationToken,通过从 HttpServletRequest 中提取用户名和密码。

UsernamePasswordAuthenticationToken 是 Authentication 认证对象的一个具体实现类

  1. 接下来 UsernamePasswordAuthenticationToken 会被传入 AuthenticationManager 认证管理器中进行认证处理,如何进行认证取决于用户对象的存储方法。

  2. 如果认证失败

    1. SecurityContextHolder 被清除。
    2. 调用记住我 RememberMeServices.loginFail,如果没有配置则不会调用
    3. AuthenticationFailureHandler 认证失败处理器会被调用。
  3. 如果认证成功

    1. SessionAuthenticationStrategy 认证会话策略收到新登录的通知。
    2. Authentication 认证对象会被保存到 SecurityContextHolder 安全上下文持有者中。
    3. RememberMeServices.loginSuccess 记住我被调用,如果没配置则不会
    4. ApplicationEventPublisher 发布登录成功事件 InteractiveAuthenticationSuccessEvent
    5. 接着调用 AuthenticationSuccessHandler 登录成功处理器,常用实现是 SimpleUrlAuthenticationSuccessHandler。当我们登录成功后,它会帮我们重定向到 ExceptionTranslationFilter 保存的登录请求之前的页面。

默认情况下启用表单登录,但是如果一但提供了基于 Servlet 的配置,就必须明确提供基于表单的登录,下面是一个示例配置:

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(withDefaults());
	// ...
}

默认 Security 会提供一个登录页面,基本项目开发都会有自己的登录页面。

下面配置演示了如何提供自定义登录页面:

public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		.formLogin(form -> form
			.loginPage("/login")
			.permitAll()
		);
	// ...
}

默认是通过 Thymeleaf 来生成登录页面,路径:src/main/resources/templates/login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
	<head>
		<title>Please Log In</title>
	</head>
	<body>
		<h1>Please Log In</h1>
		<div th:if="${param.error}">
			Invalid username and password.</div>
		<div th:if="${param.logout}">
			You have been logged out.</div>
		<form th:action="@{/login}" method="post">
			<div>
			<input type="text" name="username" placeholder="Username"/>
			</div>
			<div>
			<input type="password" name="password" placeholder="Password"/>
			</div>
			<input type="submit" value="Log in" />
		</form>
	</body>
</html>

默认登录表单说明:

  • 该表单会发送 post 请求到 /login 来进行登录
  • 该表单包含一个 CSRF 令牌,这是 Thymeleaf 默认提供的
  • 默认使用 username 和 password 来进行登录

以上是默认内容我们都可以通过自定义配置来进行配置。

如果你正在使用 SpringMVC 通过通过 Controller 控制器返回 login 路径来访问默认的登录页面,示例:

@Controller
class LoginController {
	@GetMapping("/login")
	String login() {
		return "login";
	}
}
基本认证

本节介绍了 Spring Security 为基于 Servlet 的应用程序提供了基本的 HTTP 认证支持。

查看下图,我们可以清楚的看到 SpringSecurity 对 HTTP 基础认证的工作原理,我们可以清楚的看到 WWW-Authenticate 的头会被发送回未经身份验证的客户端。

在这里插入图片描述

认证也是基于 SecurityFilterChain 过滤器链:

  • 首先,未经过身份验证的用户向未授权的 /private 接口发起请求
  • Spring Security 的 FilterSecurityInterceptor 通过抛出 AccessDeniedException 异常来拒绝未经过身份认证的请求
  • 由于用户未认证,ExceptionTranslationFilter 会开启身份认证,配置的 AuthenticationEntryPoint 认证入口点实现是 BasicAuthenticationEntryPoint 的一个实例,他会发送 WWW-Authenticate 头返回回客户端,并且 RequestCache 请求为空。请求重定向由客户端去实现。

当客户端收到 WWW-Authenticate 头时,表示需要身份认证后才能访问请求接口,并且使用用户名和密码来进行身份认证。

在这里插入图片描述

认证流程,基于 SecurityFilterChain 过滤器链:

  1. 当用户进行身份验证请求时,BasicAuthenticationFilter 会创建一个 UsernamePasswordAuthenticationToken 认证对象,此对象的创建也是通过从 HttpServletRequest 中提取用户名和密码来实现的。

  2. 接下来 UsernamePasswordAuthenticationToken 会被传入 AuthenticationManager 中进行身份验证,AuthenticationManager 如何进行验证取决于用户如何存储的。

  3. 如果认证失败

    1. SecurityContextHolder 被清除。
    2. 调用记住我 RememberMeServices.loginFail,如果没有配置则不会调用
    3. 调用 AuthenticationEntryPoint 再次发送 WWW-Authenticate 头到客户端
  4. 如果认证成功

    1. Authentication 被保存在 SecurityContextHolder 中。
    2. RememberMeServices.loginSuccess 记住我被调用,如果没配置则不会
    3. BasicAuthenticationFilter 调用 FilterChain.doFilter(request,response) 来继续其余的应用程序逻辑。

默认情况下,Spring Security 的 HTTP 基本身份验证支持是启用的。然而,一旦提供了任何基于 servlet 的配置,就必须显式地提供HTTP Basic。

示例:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) {
	http
		// ...
		.httpBasic(withDefaults());
	return http.build();
}
摘要式身份验证
密码存储
持续身份验证
会话管理
记住我认证
OpenID 支持
匿名认证
预认证场景
Java 身份验证和授权服务 (JAAS) 提供程序
CAS认证
X.509 身份验证
运行身份验证替换
处理注销
认证事件

授权

Spring Security 中的高级授权功能是其受欢迎的最令人信服的原因之一。 无论您选择如何进行身份验证 - 无论是使用 Spring Security 提供的机制和提供者,还是与容器或其他非 Spring Security 身份验证权限集成 - 您都会发现授权服务可以在您的应用程序中以一致且简单的方式使用。

在这一部分中,我们将探索不同的 AbstractSecurityInterceptor 抽象安全拦截器 实现,这些实现在第一部分中已经介绍过了。

授权架构

Authentication 身份认证对象,身份认证对象存储了 GrantedAuthority 授权对象列表,AuthenticationManager 会把 GrantedAuthority 授权对象插入到 Authentication 认证对象中。然后 AuthorizationManager 在做出权限认证时,会取出认证对象里存储的权限对象。

GrantedAuthority 是一个只有一个方法的接口:

String getAuthority();

此方法允许 AuthorizationManagers 获得 GrantedAuthority 权限对象的精确字符串。大多数 AuthorizationManagers 和AccessDecisionManagers 可以轻松地 “读取” GrantedAuthority。如果 GrantedAuthority 不能精确地表示为字符串,则 GrantedAuthority 被认为是 “复杂的”, getAuthority() 必须返回 null。

复杂的 GrantedAuthority 如不同的用户账户的操作和权限列表。如果很难把权限表示为字符串,GrantedAuthority 会返回 null。我们需要专门实现 GrantedAuthority 对象,并且向所有的 AuthorizationManager 授权管理器表明我们有自定义权限对象,以便权限管理器使用。

Spring Security 有一个具体的实现 SimpleGrantedAuthority,它允许将用户给定的字符串转换为 GrantedAuthority 权限对象。在 Security 中 AuthenticationProviders 身份验证提供者都使用默认的 SimpleGrantedAuthority 权限对象来填充身份验证对象。

调用前处理

Spring Security 提供了拦截器来控制对安全对象的访问,比如方法调用或 web 请求。由 AccessDecisionManager 来处理是否允许继续调用。

AuthorizationManager:授权管理器

AuthorizationManager 取代了 AccessDecisionManager 和 AccessDecisionVoter。

鼓励自定义 AccessDecisionManager 或 AccessDecisionVoter 的应用程序更改为使用 AuthorizationManager。

在做权限认证时 AuthorizationFilter,会调用 AuthorizationManagers 来处理权限认证,AuthorizationManager 接口包含两种方法。

AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);

default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
        throws AccessDeniedException {
    AuthorizationDecision decision = check(authentication, object);
    if (decision != null && !decision.isGranted()) {
        throw new AccessDeniedException("Access Denied");
    }
}

check 方法用于授权处理,我们可以通过传入安全对象,在做权限处理时,可以获取到安全对象中的属性。例如:我们传入的是一个 MethodInvocation 方法安全对象。我们可以在 AuthorizationManager 中获取到传入的 MethodInvocation 方法安全对象中的参数,并且在 AuthorizationManager 授权管理器中实现我们的安全逻辑。如果允许访问,其实例将返回一个通过的 AuthorizationDecision 授权决策,如果访问拒绝,则返回拒绝的 AuthorizationDecision 授权决策,如果放弃做出决策,则返回一个 NULL 的 AuthorizationDecision。

verify 会调用 check 方法,并且在 AuthorizationDecision 为拒绝访问的情况下,抛出 AccessDeniedException 异常。

基于委托的 AuthorizationManager 授权管理器实现

虽然用户可以自定义 AuthorizationManager 授权管理器,来实现自己的授权认证,但 SpringSecurity 附带了一个委托 AuthorizationManager 授权管理器,并且它可以和各个 AuthorizationManager 授权管理器合作。

RequestMatcherDelegatingAuthorizationManager 请求匹配委托授权管理器会将请求与合适的委托 AuthorizationManager 授权管理器进行匹配。对于方法安全,可以使用 AuthorizationManagerBeforeMethodInterceptor 和 AuthorizationManagerAfterMethodInterceptor。

Spring Security 提供了 7 个 AuthorizationManager 授权管理器的实现类:

在这里插入图片描述

我们可以使用 AuthorizationManager 不同实现类来组合授权。

AuthorityAuthorizationManager

AuthorityAuthorizationManager 是 SpringSecurity 提供的最常见的 AuthorizationManager 实现类,它配置了一组给定的权限集合来进行权限验证,如果用户的 Authentication 对象的权限和给定的权限集合有值相匹配,则会返回 true 的 AuthorizationDecision 授权决定,否则返回 false 的 AuthorizationDecision 授权决定。

AuthenticatedAuthorizationManager

AuthenticatedAuthorizationManager 是认证授权管理器。它可以用来区分是匿名用户还是记住我用户,许多网站在记住我身份验证下只有有限的权限,只有当用户登录后才能获取完整的权限。

自定义授权管理器

我们可以实现 AuthorizationManager 接口,来自定义其权限验证的实现。例如:我们可以根据自己的授权数据库来进行授权管理逻辑。

当然我们也可以使用老版的 AccessDecisionVoter 类来实现自定义授权逻辑

调整 AccessDecisionManager 和 AccessDecisionVoters

在 AuthorizationManager 之前,Spring Security 发布了 AccessDecisionManager 和 AccessDecisionVoter。

在一些升级旧的项目中,我们可以需要一个 AuthorizationManager 来调用 AccessDecisionManager 和 AccessDecisionVoter。

如果要调用现有的 AccessDecisionManager 你可以这么做:

@Component
public class AccessDecisionManagerAuthorizationManagerAdapter implements AuthorizationManager {
    private final AccessDecisionManager accessDecisionManager;
    private final SecurityMetadataSource securityMetadataSource;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
        try {
            Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
            this.accessDecisionManager.decide(authentication.get(), object, attributes);
            return new AuthorizationDecision(true);
        } catch (AccessDeniedException ex) {
            return new AuthorizationDecision(false);
        }
    }

    @Override
    public void verify(Supplier<Authentication> authentication, Object object) {
        Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
        this.accessDecisionManager.decide(authentication.get(), object, attributes);
    }
}

然后把它加入你的 SecurityFilterChain 安全过滤器链上。

如果只调用 AccessDecisionVoter 你可以这样:

@Component
public class AccessDecisionVoterAuthorizationManagerAdapter implements AuthorizationManager {
    private final AccessDecisionVoter accessDecisionVoter;
    private final SecurityMetadataSource securityMetadataSource;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
        Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
        int decision = this.accessDecisionVoter.vote(authentication.get(), object, attributes);
        switch (decision) {
        case ACCESS_GRANTED:
            return new AuthorizationDecision(true);
        case ACCESS_DENIED:
            return new AuthorizationDecision(false);
        }
        return null;
    }
}

记得把它加入 SpringSecurity 的安全过滤器链中。

分层角色

在程序开发中,可能会出现角色包含的情况,比如一个父角色包含其它子角色。比如管理员和普通用户,你可能会要求管理员也有普通用户的权限。因此你可能会分配给此用户,管理员和普通用户的权限。有可能是用户角色包含管理员角色,或者管理员角色包含用户角色,当系统角色特别多时,在处理上会变得十分麻烦。

使用分层角色我们可以轻松的去包含其它子角色。Spring Security 的 RoleVoter 的扩展版本 RoleHierarchyVoter 配置了 RoleHierarchy,从中获取分配给用户的所有“可访问权限”。 典型的配置可能如下所示:

@Bean
AccessDecisionVoter hierarchyVoter() {
    RoleHierarchy hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
            "ROLE_STAFF > ROLE_USER\n" +
            "ROLE_USER > ROLE_GUEST");
    return new RoleHierarchyVoter(hierarchy);
}

上面实例有四个角色权限 ROLE_ADMIN、ROLE_STAFF、ROLE_USER、ROLE_GUEST,其中 ROLE_ADMIN 是顶层角色,当用户被授予了 ROLE_ADMIN,则此用户还可以拥有剩下的三个角色的权限。> 符号是包含的意思。

Spring Security 提供角色分层赋予来简化分层角色的配置,当然我们也可以根据自己的业务情况来使用。

旧版授权组件

Spring Security 包含一些遗留的旧版组件,并且并没有在项目中删除,推荐使用上面的新版授权组件

AccessDecisionManager

AccessDecisionManager 由 AbstractSecurityInterceptor 调用,负责做出最终的访问控制决策。 AccessDecisionManager 接口包含三个方法:

void decide(Authentication authentication, Object secureObject,
	Collection<ConfigAttribute> attrs) throws AccessDeniedException;

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

AccessDecisionManager 的 decide 方法传入了授权需要的全部信息,并通过这些信息来进行授权操作。传递了 secureObject 安全对象,以便在安全对象被调用时可以检查其中的参数,例如:我们假设安全对象为 MethodInvocation 方法对象。我们可以通过 MethodInvocation 对象很容易的获得任何用户参数,然后在 AccessDecisionManager 中实现某种安全逻辑,以确定是否允许操作,如果访问被拒绝,我们应该在其实现类中抛出 AccessDeniedException 异常。

AbstractSecurityInterceptor 在启动时会调用 supports(ConfigAttribute) 方法,以确定 AccessDecisionManager 是否可以处理传递的ConfigAttribute。supports(Class) 方法由 security interceptor 安全拦截器实现调用,以确保配置的 AccessDecisionManager 支持 security interceptor 安全拦截器将呈现的安全对象的类型。

基于投票的 AccessDecisionManager 实现

虽然用户可以实现自己的 AccessDecisionManager 来控制授权,但是 Spring Security 提供了几个基于投票的 AccessDecisionManager 实现。 下图 Voting Decision Manager 投票决策管理器演示了相关的类。

在这里插入图片描述

RoleVoter:角色投票者
AuthenticatedVoter:认证投票人
Custom Voters:自定义选民
使用 AuthorizationFilter 授权 http servlet 请求

本节深入讨论基于 Servlet 的应用程序的授权是如何工作的。以Servlet架构和实现为基础。

AuthorizationFilter 取代了 FilterSecurityInterceptor。为了保持向后兼容,FilterSecurityInterceptor 仍然是默认的。本节讨论AuthorizationFilter 如何工作以及如何覆盖默认配置。

AuthorizationFilter 为 HttpServletRequests 提供授权。它作为 Security Filters 安全过滤器之一插入到 FilterChainProxy 中。

当声明 SecurityFilterChain 时,可以重写默认值。不使用 authorizeRequests(授权请求),而是使用 authorizeHttpRequests(授权Http请求),如下所示:

@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated();
        )
        // ...

    return http.build();
}

它在许多方面改进了 authorizeRequests(授权请求):

  • 使用简化的 AuthorizationManager API,而不是元数据源、配置属性、决策管理器和投票器。这简化了重用和定制
  • 延迟 Authentication 身份验证查找。不是每个请求都需要查找身份验证,而是只在授权决策需要身份验证的请求中查找。
  • 配置Bean的支持。

当使用 authorizeHttpRequests 而不是 authorizeRequests 时,则使用 AuthorizationFilter 而不是 FilterSecurityInterceptor。

在这里插入图片描述

  1. 首先,AuthorizationFilter 认证过滤器从 SecurityContextHolder 中获得一个 Authentication,它将其包装在 Supplier 供应者中以延迟查找。
  2. 其次,AuthorizationFilter 从 HttpServletRequest、HttpServletResponse 和 FilterChain 创建一个 FilterInvocation。
  3. 接下来,它将 Supplier<Authentication> 和 FilterInvocation 传递给 AuthorizationManager。
    1. 如果授权被拒绝,将抛出 AccessDeniedException。在这种情况下,ExceptionTranslationFilter 会处理 AccessDeniedException。
    2. 如果授予通过,AuthorizationFilter 将继续使用过滤器链,从而允许应用程序正常处理。

我们可以通过优先级添加更多的规则来配置 Spring Security,使其具有不同的规则。

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
	http
		// ...
		.authorizeHttpRequests(authorize -> authorize               		// 1                   
			.mvcMatchers("/resources/**", "/signup", "/about").permitAll()  // 2     
			.mvcMatchers("/admin/**").hasRole("ADMIN")                      // 3    
			.mvcMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")   // 4
			.anyRequest().denyAll()                                          // 5
		);

	return http.build();
}
  1. 指定了多个授权规则。每个规则都是按照它们被声明的顺序来考虑的。
  2. 我们指定了多个 URL 配置,指定 URL 以 /resources开头,或等于 /signup/about的路径,任何用户都可以访问
  3. 任何以 /admin/” 开头的 URL 都将限于角色为 ROLE_ADMIN` 的用户。您会注意到,由于我们正在调用 hasRole 方法,所以不需要指定 “ROLE_” 前缀。
  4. 任何以 “/db/” 开头的 URL 都要求用户同时拥有 “ROLE_ADMIN” 和 “ROLE_DBA” 。 您会注意到,由于我们使用了 hasRole 表达式,我们不需要指定 “ROLE_” 前缀。
  5. 任何未配置的路径都将被拒绝

您可以采用基于 bean 的方法,来构造自己的 RequestMatcherDelegatingAuthorizationManager,如下所示:

@Bean
SecurityFilterChain web(HttpSecurity http, AuthorizationManager<RequestAuthorizationContext> access)
        throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().access(access)
        )
        // ...

    return http.build();
}

@Bean
AuthorizationManager<RequestAuthorizationContext> requestMatcherAuthorizationManager(HandlerMappingIntrospector introspector) {
    // 使用方法来构建匹配规则
    RequestMatcher permitAll =
            new AndRequestMatcher(
                    new MvcRequestMatcher(introspector, "/resources/**"),
                    new MvcRequestMatcher(introspector, "/signup"),
                    new MvcRequestMatcher(introspector, "/about"));
    RequestMatcher admin = new MvcRequestMatcher(introspector, "/admin/**");
    RequestMatcher db = new MvcRequestMatcher(introspector, "/db/**");
    RequestMatcher any = AnyRequestMatcher.INSTANCE;
    AuthorizationManager<HttpRequestServlet> manager = RequestMatcherDelegatingAuthorizationManager.builder()
            .add(permitAll, (context) -> new AuthorizationDecision(true))
            .add(admin, AuthorityAuthorizationManager.hasRole("ADMIN"))
            .add(db, AuthorityAuthorizationManager.hasRole("DBA"))
            .add(any, new AuthenticatedAuthorizationManager())
            .build();
    return (context) -> manager.check(context.getRequest());
}

您还可以为任何请求匹配器连接您自己的自定义授权管理器。

以下是将自定义授权管理器映射到 my/authorized/endpoint 的示例:

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .mvcMatchers("/my/authorized/endpoint").access(new CustomAuthorizationManager());
        )
        // ...

    return http.build();
}

CustomAuthorizationManager 自定义授权管理器

或者你可以匹配所有请求:

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest.access(new CustomAuthorizationManager());	// 自定义授权管理器
        )
        // ...

    return http.build();
}

默认情况下,AuthorizationFilter 不适用于 DispatcherType.ERROR 和 DispatcherType.ASYNC。 我们可以使用 shouldFilterAllDispatcherTypes 方法配置 Spring Security 以将授权规则应用于所有调度程序类型:

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .shouldFilterAllDispatcherTypes(true)
            .anyRequest.authenticated()
        )
        // ...

    return http.build();
}
使用 FilterSecurityInterceptor 授权 HttpServletRequest
基于表达式的访问控制
安全对象实现
Method 安全
Domain 对象安全 (ACL)
授权事件

OAuth2

SAML2

防止漏洞利用

集成

配置

测试

附录

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security-3.0.1 中文官方文档(翻译版) 这次发布的Spring Security-3.0.1 是一个bug fix 版,主要是对3.0 中存在的一些问题进 行修 正。文档中没有添加新功能的介绍,但是将之前拼写错误的一些类名进行了修正,建议开发 者以这一版本的文档为参考。 另:Spring Security 从2010-01-01 以后,版本控制从SVN 换成了GIT,我们在翻译文档的 时候,主要是根据SVN 的变化来进行文档内容的比对,这次换成GIT 后,感觉缺少了之前 那种文本比对工具,如果有对GIT 熟悉的朋友,还请推荐一下文本比对的工具,谢谢。 序言 I. 入门 1. 介绍 1.1. Spring Security 是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. Config - spring-security-config.jar 1.4.1.4. LDAP - spring-security-ldap.jar 1.4.1.5. ACL - spring-security-acl.jar 1.4.1.6. CAS - spring-security-cas-client.jar 1.4.1.7. OpenID - spring-security-openid.jar 1.4.2. 获得源代码 2. Security 命名空间配置 2.1. 介绍 2.1.1. 命名空间的设计 2.2. 开始使用安全命名空间配置 2.2.1. 配置web.xml 2.2.2. 最小 配置 2.2.2.1. auto-config 包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web 特性 2.3.1. Remember-Me 认证 2.3.2. 添加HTTP/HTTPS 信道安全 2.3.3. 会话管理 2.3.3.1. 检测超时 2.3.3.2. 同步会话控制 2.3.3.3. 防止Session 固定攻击 2.3.4. 对OpenID 的支持 2.3.4.1. 属性交换 2.3.5. 添加你自己的filter 2.3.5.1. 设置自定义AuthenticationEntryPoint 2.4. 保护方法 2.4.1. 元素 2.4.1.1. 使用protect-pointcut 添加安全切点 2.5. 默认的AccessDecisionManager 2.5.1. 自定义AccessDecisionManager 2.6. 验证管理器和命名空间 3. 示例程序 3.1. Tutorial 示例 3.2. Contacts 3.3. LDAP 例子 3.4. CAS 例子 3.5. Pre-Authentication 例子 4. Spring Security 社区 4.1. 任务跟踪 4.2. 成为参与者 4.3. 更多信息 II. 结构和实现 5. 技术概述 5.1. 运行环境 5.2. 核心组件 5.2.1. SecurityContextHolder, SecurityContext 和Authentication 对象 5.2.1.1. 获得当前用户的信息 5.2.2. UserDetailsService 5.2.3. GrantedAuthority 5.2.4. 小结 5.3. 验证 5.3.1. 什么是Spring Security 的验证呢? 5.3.2. 直接设置SecurityContextHolder 的内容 5.4. 在web 应用中验证 5.4.1. ExceptionTranslationFilter 5.4.2. AuthenticationEntryPoint 5.4.3. 验证机制 5.4.4. 在请求之间保存SecurityContext 。 5.5. Spring Security 中的访问控制(验证) 5.5.1. 安全和AOP 建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager 5.5.2.4. 扩展安全对象模型 5.6. 国际化 6. 核心服务 6.1. The AuthenticationManager , ProviderManager 和AuthenticationProvider s 6.1.1. DaoAuthenticationProvider 6.2. UserDetailsService 实现 6.2.1. 内存认证 6.2.2. JdbcDaoImpl 6.2.2.1. 权限分组 6.3. 密码加密 6.3.1. 什么是散列加密? 6.3.2. 为散列加点儿盐 6.3.3. 散列和认证 III. web 应用安全 7. 安全过滤器链 7.1. DelegatingFilterProxy 7.2. FilterChainProxy 7.2.1. 绕过过滤器链 7.3. 过滤器顺序 7.4. 使用其他过滤器—— 基于框架 8. 核心安全过滤器 8.1. FilterSecurityInterceptor 8.2. ExceptionTranslationFilter 8.2.1. AuthenticationEntryPoint 8.2.2. AccessDeniedHandler 8.3. SecurityContextPersistenceFilter 8.3.1. SecurityContextRepository 8.4. UsernamePasswordAuthenticationFilter 8.4.1. 认证成功和失败的应用流程 9. Basic(基本)和Digest(摘要)验证 9.1. BasicAuthenticationFilter 9.1.1. 配置 9.2. DigestAuthenticationFilter 9.2.1. Configuration 10. Remember-Me 认证 10.1. 概述 10.2. 简单基于散列标记的方法 10.3. 持久化标记方法 10.4. Remember-Me 接口和实现 10.4.1. TokenBasedRememberMeServices 10.4.2. PersistentTokenBasedRememberMeServices 11. 会话管理 11.1. SessionManagementFilter 11.2. SessionAuthenticationStrategy 11.3. 同步会话 12. 匿名认证 12.1. 概述 12.2. 配置 12.3. AuthenticationTrustResolver IV. 授权 13. 验证架构 13.1. 验证 13.2. 处理预调用 13.2.1. AccessDecisionManager 13.2.2. 基于投票的AccessDecisionManager 实现 13.2.2.1. RoleVoter 13.2.2.2. AuthenticatedVoter 13.2.2.3. Custom Voters 13.3. 处理后决定 14. 安全对象实现 14.1. AOP 联盟(MethodInvocation) 安全拦截器 14.1.1. 精确的MethodSecurityIterceptor 配置 14.2. AspectJ (JoinPoint) 安全拦截器 15. 基于表达式的权限控制 15.1. 概述 15.1.1. 常用内建表达式 15.2. Web 安全表达式 15.3. 方法安全表达式 15.3.1. @Pre 和@Post 注解 15.3.1.1. 访问控制使用@PreAuthorize 和@PostAuthorize 15.3.1.2. 过滤使用@PreFilter 和@PostFilter 16. acegi 到spring security 的转换方式 16.1. Spring Security 是什么 16.2. 目标 16.3. 步骤 16.4. 总结 V. 高级话题 17. 领域对象安全(ACLs) 17.1. 概述 17.2. 关键概念 17.3. 开始 18. 预认证场景 18.1. 预认证框架类 18.1.1. AbstractPreAuthenticatedProcessingFilter 18.1.2. AbstractPreAuthenticatedAuthenticationDetailsSource 18.1.2.1. J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 18.1.3. PreAuthenticatedAuthenticationProvider 18.1.4. Http403ForbiddenEntryPoint 18.2. 具体实现 18.2.1. 请求头认证(Siteminder) 18.2.1.1. Siteminder 示例配置 18.2.2. J2EE 容器认证 19. LDAP 认证 19.1. 综述 19.2. 在Spring Security 里使用LDAP 19.3. 配置LDAP 服务器 19.3.1. 使用嵌入测试服务器 19.3.2. 使用绑定认证 19.3.3. 读取授权 19.4. 实现类 19.4.1. LdapAuthenticator 实现 19.4.1.1. 常用功能 19.4.1.2. BindAuthenticator 19.4.1.3. PasswordComparisonAuthenticator 19.4.1.4. 活动目录认证 19.4.2. 链接到LDAP 服务器 19.4.3. LDAP 搜索对象 19.4.3.1. FilterBasedLdapUserSearch 19.4.4. LdapAuthoritiesPopulator 19.4.5. Spring Bean 配置 19.4.6. LDAP 属性和自定义UserDetails 20. JSP 标签库 20.1. 声明Taglib 20.2. authorize 标签 20.3. authentication 标签 20.4. accesscontrollist 标签 21. Java 认证和授权服务(JAAS)供应器 21.1. 概述 21.2. 配置 21.2.1. JAAS CallbackHandler 21.2.2. JAAS AuthorityGranter 22. CAS 认证 22.1. 概述 22.2. CAS 是如何工作的 22.3. 配置CAS 客户端 23. X.509 认证 23.1. 概述 23.2. 把X.509 认证添加到你的web 系统中 23.3. 为tomcat 配置SSL 24. 替换验证身份 24.1. 概述 24.2. 配置 A. 安全数据库表结构 A.1. User 表 A.1.1. 组权限 A.2. 持久登陆(Remember-Me)表 A.3. ACL 表 A.3.1. Hypersonic SQL A.3.1.1. PostgreSQL B. 安全命名空间 B.1. Web 应用安全- 元素 B.1.1. 属性 B.1.1.1. servlet-api-provision B.1.1.2. path-type B.1.1.3. lowercase-comparisons B.1.1.4. realm B.1.1.5. entry-point-ref B.1.1.6. access-decision-manager-ref B.1.1.7. access-denied-page B.1.1.8. once-per-request B.1.1.9. create-session B.1.2. B.1.3. 元素 B.1.3.1. pattern B.1.3.2. method B.1.3.3. access B.1.3.4. requires-channel B.1.3.5. filters B.1.4. 元素 B.1.5. 元素 B.1.5.1. login-page B.1.5.2. login-processing-url B.1.5.3. default-target-url B.1.5.4. always-use-default-target B.1.5.5. authentication-failure-url B.1.5.6. authentication-success-handler-ref B.1.5.7. authentication-failure-handler-ref B.1.6. 元素 B.1.7. 元素 B.1.7.1. data-source-ref B.1.7.2. token-repository-ref B.1.7.3. services-ref B.1.7.4. token-repository-ref B.1.7.5. key 属性 B.1.7.6. token-validity-seconds B.1.7.7. user-service-ref B.1.8. 元素 B.1.8.1. session-fixation-protection B.1.9. 元素 B.1.9.1. max-sessions 属性 B.1.9.2. expired-url 属性 B.1.9.3. error-if-maximum-exceeded 属性 B.1.9.4. session-registry-alias 和session-registry-ref 属性 B.1.10. 元素 B.1.11. 元素 B.1.11.1. subject-principal-regex 属性 B.1.11.2. user-service-ref 属性 B.1.12. 元素 B.1.13. 元素 B.1.13.1. logout-url 属性 B.1.13.2. logout-success-url 属性 B.1.13.3. invalidate-session 属性 B.1.14. 元素 B.2. 认证服务 B.2.1. 元素 B.2.1.1. 元素 B.2.1.2. 使用 来引用一个AuthenticationProvider Bean B.3. 方法安全 B.3.1. 元素 B.3.1.1. secured-annotations 和jsr250-annotations 属性 B.3.1.2. 安全方法使用 B.3.1.3. 元素 B.3.2. LDAP 命名空间选项 B.3.2.1. 使用 元素定义LDAP 服务器 B.3.2.2. 元素 B.3.2.3. 元素
序言 I. 入门 1. 介绍 1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. Config - spring-security-config.jar 1.4.1.4. LDAP - spring-security-ldap.jar 1.4.1.5. ACL - spring-security-acl.jar 1.4.1.6. CAS - spring-security-cas-client.jar 1.4.1.7. OpenID - spring-security-openid.jar 1.4.2. 获得源代码 2. Security命名空间配置 2.1. 介绍 2.1.1. 命名空间的设计 2.2. 开始使用安全命名空间配置 2.2.1. 配置web.xml 2.2.2. 最小 <http>配置 2.2.2.1. auto-config包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web特性 2.3.1. Remember-Me认证 2.3.2. 添加HTTP/HTTPS信道安全 2.3.3. 会话管理 2.3.3.1. 检测超时 2.3.3.2. 同步会话控制 2.3.3.3. 防止Session固定攻击 2.3.4. 对OpenID的支持 2.3.4.1. 属性交换 2.3.5. 添加你自己的filter 2.3.5.1. 设置自定义 AuthenticationEntryPoint 2.4. 保护方法 2.4.1. <global-method-security>元素 2.4.1.1. 使用protect-pointcut添加安全切点 2.5. 默认的AccessDecisionManager 2.5.1. 自定义AccessDecisionManager 2.6. 验证管理器和命名空间 3. 示例程序 3.1. Tutorial示例 3.2. Contacts 3.3. LDAP例子 3.4. CAS例子 3.5. Pre-Authentication例子 4. Spring Security社区 4.1. 任务跟踪 4.2. 成为参与者 4.3. 更多信息 II. 结构和实现 5. 技术概述 5.1. 运行环境 5.2. 核心组件 5.2.1. SecurityContextHolder, SecurityContext 和 Authentication对象 5.2.1.1. 获得当前用户的信息 5.2.2. UserDetailsService 5.2.3. GrantedAuthority 5.2.4. 小结 5.3. 验证 5.3.1. 什么是Spring Security的验证呢? 5.3.2. 直接设置SecurityContextHolder的内容 5.4. 在web应用中验证 5.4.1. ExceptionTranslationFilter 5.4.2. AuthenticationEntryPoint 5.4.3. 验证机制 5.4.4. 在请求之间保存SecurityContext。 5.5. Spring Security中的访问控制(验证) 5.5.1. 安全和AOP建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager 5.5.2.4. 扩展安全对象模型 5.6. 国际化 6. 核心服务 6.1. The AuthenticationManager, ProviderManager 和 AuthenticationProviders 6.1.1. DaoAuthenticationProvider 6.2. UserDetailsService实现 6.2.1. 内存认证 6.2.2. JdbcDaoImpl 6.2.2.1. 权限分组 6.3. 密码加密 6.3.1. 什么是散列加密? 6.3.2. 为散列加点儿盐 6.3.3. 散列和认证 III. web应用安全 7. 安全过滤器链 7.1. DelegatingFilterProxy 7.2. FilterChainProxy 7.2.1. 绕过过滤器链 7.3. 过滤器顺序 7.4. 使用其他过滤器 —— 基于框架 8. 核心安全过滤器 8.1. FilterSecurityInterceptor 8.2. ExceptionTranslationFilter 8.2.1. AuthenticationEntryPoint 8.2.2. AccessDeniedHandler 8.3. SecurityContextPersistenceFilter 8.3.1. SecurityContextRepository 8.4. UsernamePasswordAuthenticationFilter 8.4.1. 认证成功和失败的应用流程 9. Basic(基本)和Digest(摘要)验证 9.1. BasicAuthenticationFilter 9.1.1. 配置 9.2. DigestAuthenticationFilter 9.2.1. Configuration 10. Remember-Me认证 10.1. 概述 10.2. 简单基于散列标记的方法 10.3. 持久化标记方法 10.4. Remember-Me接口和实现 10.4.1. TokenBasedRememberMeServices 10.4.2. PersistentTokenBasedRememberMeServices 11. 会话管理 11.1. SessionManagementFilter 11.2. SessionAuthenticationStrategy 11.3. 同步会话 12. 匿名认证 12.1. 概述 12.2. 配置 12.3. AuthenticationTrustResolver IV. 授权 13. 验证架构 13.1. 验证 13.2. 处理预调用 13.2.1. AccessDecisionManager 13.2.2. 基于投票的AccessDecisionManager实现 13.2.2.1. RoleVoter 13.2.2.2. AuthenticatedVoter 13.2.2.3. Custom Voters 13.3. 处理后决定 14. 安全对象实现 14.1. AOP联盟 (MethodInvocation) 安全拦截器 14.1.1. 精确的 MethodSecurityIterceptor 配置 14.2. AspectJ (JoinPoint) 安全拦截器 15. 基于表达式的权限控制 15.1. 概述 15.1.1. 常用内建表达式 15.2. Web 安全表达式 15.3. 方法安全表达式 15.3.1. @Pre 和 @Post 注解 15.3.1.1. 访问控制使用 @PreAuthorize 和 @PostAuthorize 15.3.1.2. 过滤使用 @PreFilter 和 @PostFilter V. 高级话题 16. 领域对象安全(ACLs) 16.1. 概述 16.2. 关键概念 16.3. 开始 17. 预认证场景 17.1. 预认证框架类 17.1.1. AbstractPreAuthenticatedProcessingFilter 17.1.2. AbstractPreAuthenticatedAuthenticationDetailsSource 17.1.2.1. J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 17.1.3. PreAuthenticatedAuthenticationProvider 17.1.4. Http403ForbiddenEntryPoint 17.2. 具体实现 17.2.1. 请求头认证(Siteminder) 17.2.1.1. Siteminder示例配置 17.2.2. J2EE容器认证 18. LDAP认证 18.1. 综述 18.2. 在Spring Security里使用LDAP 18.3. 配置LDAP服务器 18.3.1. 使用嵌入测试服务器 18.3.2. 使用绑定认证 18.3.3. 读取授权 18.4. 实现类 18.4.1. LdapAuthenticator实现 18.4.1.1. 常用功能 18.4.1.2. BindAuthenticator 18.4.1.3. PasswordComparisonAuthenticator 18.4.1.4. 活动目录认证 18.4.2. 链接到LDAP服务器 18.4.3. LDAP搜索对象 18.4.3.1. FilterBasedLdapUserSearch 18.4.4. LdapAuthoritiesPopulator 18.4.5. Spring Bean配置 18.4.6. LDAP属性和自定义UserDetails 19. JSP标签库 19.1. 声明Taglib 19.2. authorize标签 19.3. authentication 标签 19.4. accesscontrollist 标签 20. Java认证和授权服务(JAAS)供应器 20.1. 概述 20.2. 配置 20.2.1. JAAS CallbackHandler 20.2.2. JAAS AuthorityGranter 21. CAS认证 21.1. 概述 21.2. CAS是如何工作的 21.3. 配置CAS客户端 22. X.509认证 22.1. 概述 22.2. 把X.509认证添加到你的web系统中 22.3. 为tomcat配置SSL 23. 替换验证身份 23.1. 概述 23.2. 配置 A. 安全数据库表结构 A.1. User表 A.1.1. 组权限 A.2. 持久登陆(Remember-Me)表 A.3. ACL表 A.3.1. Hypersonic SQL A.3.1.1. PostgreSQL B. 安全命名空间 B.1. Web应用安全 - <http>元素 B.1.1. <http>属性 B.1.1.1. servlet-api-provision B.1.1.2. path-type B.1.1.3. lowercase-comparisons B.1.1.4. realm B.1.1.5. entry-point-ref B.1.1.6. access-decision-manager-ref B.1.1.7. access-denied-page B.1.1.8. once-per-request B.1.1.9. create-session B.1.2. <access-denied-handler> B.1.3. <intercept-url>元素 B.1.3.1. pattern B.1.3.2. method B.1.3.3. access B.1.3.4. requires-channel B.1.3.5. filters B.1.4. <port-mappings>元素 B.1.5. <form-login>元素 B.1.5.1. login-page B.1.5.2. login-processing-url B.1.5.3. default-target-url B.1.5.4. always-use-default-target B.1.5.5. authentication-failure-url B.1.5.6. authentication-success-handler-ref B.1.5.7. authentication-failure-handler-ref B.1.6. <http-basic>元素 B.1.7. <remember-me>元素 B.1.7.1. data-source-ref B.1.7.2. token-repository-ref B.1.7.3. services-ref B.1.7.4. token-repository-ref B.1.7.5. key属性 B.1.7.6. token-validity-seconds B.1.7.7. user-service-ref B.1.8. <session-management> 元素 B.1.8.1. session-fixation-protection B.1.9. <concurrent-control>元素 B.1.9.1. max-sessions属性 B.1.9.2. expired-url属性 B.1.9.3. error-if-maximum-exceeded属性 B.1.9.4. session-registry-alias和session-registry-ref属性 B.1.10. <anonymous>元素 B.1.11. <x509>元素 B.1.11.1. subject-principal-regex属性 B.1.11.2. user-service-ref属性 B.1.12. <openid-login>元素 B.1.13. <logout>元素 B.1.13.1. logout-url属性 B.1.13.2. logout-success-url属性 B.1.13.3. invalidate-session属性 B.1.14. <custom-filter>元素 B.2. 认证服务 B.2.1. <authentication-manager>元素 B.2.1.1. <authentication-provider>元素 B.2.1.2. 使用 <authentication-provider> 来引用一个 AuthenticationProvider Bean B.3. 方法安全 B.3.1. <global-method-security>元素 B.3.1.1. secured-annotations和jsr250-annotations属性 B.3.1.2. 安全方法使用<protect-pointcut> B.3.1.3. <after-invocation-provider> 元素 B.3.2. LDAP命名空间选项 B.3.2.1. 使用<ldap-server>元素定义LDAP服务器 B.3.2.2. <ldap-provider>元素 B.3.2.3. <ldap-user-service>元素
Spring Security 参考 1 第一部分前言 15 1.入门 16 2.介绍 17 2.1什么是Spring Security? 17 2.2历史 19 2.3版本编号 20 2.4获得Spring安全 21 2.4.1使用Maven 21 Maven仓库 21 Spring框架 22 2.4.2 Gradle 23 Gradle存储库 23 使用Spring 4.0.x和Gradle 24 2.4.3项目模块 25 核心 - spring-security-core.jar 25 远程处理 - spring-security-remoting.jar 25 Web - spring-security-web.jar 25 配置 - spring-security-config.jar 26 LDAP - spring-security-ldap.jar 26 ACL - spring-security-acl.jar 26 CAS - spring-security-cas.jar 26 OpenID - spring-security-openid.jar 26 测试 - spring-security-test.jar 26 2.4.4检出来源 26 3. Spring Security 4.2的新特性 27 3.1 Web改进 27 3.2配置改进 28 3.3杂项 28 4.样品和指南(从这里开始) 28 5. Java配置 29 5.1 Hello Web安全Java配置 29 5.1.1 AbstractSecurityWebApplicationInitializer 31 5.1.2 AbstractSecurityWebApplicationInitializer不存在Spring 31 5.1.3使用Spring MVC的AbstractSecurityWebApplicationInitializer 32 5.2 HttpSecurity 32 5.3 Java配置和表单登录 34 5.4授权请求 35 5.5处理注销 36 5.5.1 LogoutHandler 37 5.5.2 LogoutSuccessHandler 37 5.5.3更多注销相关参考 38 5.6认证 38 5.6.1内存认证 38 5.6.2 JDBC认证 39 5.6.3 LDAP认证 39 5.6.4 AuthenticationProvider 41 5.6.5 UserDetailsService 41 5.6.6 LDAP认证 41 5.7多个HttpSecurity 41 5.8方法安全性 43 5.8.1 EnableGlobalMethodSecurity 43 5.8.2 GlobalMethodSecurityConfiguration 44 5.9后处理配置的对象 45 5.10自定义DSL 46 6.安全命名空间配置 47 6.1简介 47 6.1.1命名空间的设计 49 6.2安全命名空间配置入门 50 6.2.1 web.xml配置 50 6.2.2最小的配置 50 6.2.3表单和基本登录选项 52 设置默认的登录目的地 54 6.2.4注销处理 54 6.2.5使用其他身份验证提供程序 55 添加密码编码器 56 6.3高级Web功能 56 6.3.1记得我认证 56 6.3.2添加HTTP / HTTPS通道安全 57 6.3.3会话管理 57 检测超时 57 并发会话控制 58 会话固定攻击保护 59 6.3.4 OpenID支持 60 属性交换 61 6.3.5响应头 62 6.3.6添加你自己的过滤器 62 设置一个自定义的AuthenticationEntryPoint 64 6.4方法安全 64 6.4.1 元素 65 使用protect-pointcut添加安全性切入点 66 6.5默认AccessDecisionManager 67 6.5.1自定义AccessDecisionManager 67 6.6验证管理器和命名空间 67 7.示例应用程序 69 7.1教程示例 69 7.2联系人 69 7.3 LDAP样本 71 7.4 OpenID示例 71 7.5 CAS样品 71 7.6 JAAS样品 72 7.7预认证样本 72 8. Spring Security社区 72 8.1问题跟踪 72 8.2成为参与 73 8.3更多信息 73 第二部分 架构与实现 73 9.技术概述 73 9.1运行环境 73 9.2核心组件 74 9.2.1 SecurityContextHolder,SecurityContext和认证对象 74 获取有关当前用户的信息 75 9.2.2 UserDetailsService 75 9.2.3授予权力 77 9.2.4总结 77 9.3认证 78 9.3.1什么是Spring Security中的认证? 78 9.3.2直接设置SecurityContextHolder内容 80 9.4 Web应用程序中的身份验证 81 9.4.1 ExceptionTranslationFilter 82 9.4.2 AuthenticationEntryPoint 82 9.4.3认证机制 82 9.4.4在请求之间存储SecurityContext 83 9.5 Spring Security中的访问控制(授权) 84 9.5.1安全和AOP建议 84 9.5.2安全对象和AbstractSecurityInterceptor 85 什么是配置属性? 85 RunAsManager 86 AfterInvocationManager 86 扩展安全对象模型 87 9.6本地化 87 10.核心服务 89 10.1 AuthenticationManager,ProviderManager和AuthenticationProvider 89 10.1.1成功认证时清除证书 91 10.1.2 DaoAuthenticationProvider 91 10.2 UserDetailsService实现 92 10.2.1内存认证 92 10.2.2 JdbcDaoImpl 93 权威组织 94 10.3密码编码 94 10.3.1什么是散列? 95 10.3.2添加盐到哈希 95 10.3.3散列和认证 96 10.4Jackson 支持 96 第三部分 测试 97 11.测试方法安全性 97 11.1安全测试设置 98 11.2 @WithMockUser 98 11.3 @WithAnonymousUser 100 11.4 @用户详细信息 101 11.5 @WithSecurityContext 102 11.6测试元注释 104 12. Spring MVC测试集成 104 12.1设置MockMvc和Spring Security 104 12.2 SecurityMockMvcRequestPostProcessors 105 12.2.1使用CSRF保护进行测试 105 12.2.2在Spring MVC测试中以用户身份运行测试 106 12.2.3使用RequestPostProcessor在Spring MVC测试中以用户身份运行 106 作为用户在Spring MVC测试中使用注释运行 108 12.2.4测试HTTP基本认证 109 12.3 SecurityMockMvcRequestBuilders 109 12.3.1测试基于表单的认证 109 12.3.2测试注销 110 12.4 SecurityMockMvcResultMatchers 110 12.4.1未经认证的声明 111 12.4.2认证断言 111 第四部分 Web应用程序安全 112 13.安全过滤器链 112 13.1 DelegatingFilterProxy 112 13.2 FilterChainProxy 113 13.2.1绕过滤网链 115 13.3过滤器排序 115 13.4请求匹配和HttpFirewall 116 13.5与其他基于过滤器的框架一起使用 118 13.6高级命名空间配置 118 14.核心安全筛选器 119 14.1 FilterSecurityInterceptor 119 14.2 ExceptionTranslationFilter 121 14.2.1 AuthenticationEntryPoint 122 14.2.2 AccessDeniedHandler 122 14.2.3 SavedRequest和RequestCache接口 123 14.3 SecurityContextPersistenceFilter 123 14.3.1 SecurityContextRepository 124 14.4 UsernamePasswordAuthenticationFilter 125 14.4.1认证成功与失败的应用流程 125 15. Servlet API集成 127 15.1 Servlet 2.5+集成 127 15.1.1 HttpServletRequest.getRemoteUser() 127 15.1.2 HttpServletRequest.getUserPrincipal() 127 15.1.3 HttpServletRequest.isUserInRole(String) 128 15.2 Servlet 3+集成 128 15.2.1 HttpServletRequest.authenticate(HttpServletResponse) 128 15.2.2 HttpServletRequest.login(String,String) 129 15.2.3 HttpServletRequest.logout() 129 15.2.4 AsyncContext.start(Runnable) 129 15.2.5异步Servlet支持 130 15.3 Servlet 3.1+集成 131 15.3.1 HttpServletRequest#changeSessionId() 132 16.基本和摘要式身份验证 132 16.1 BasicAuthenticationFilter 132 16.1.1配置 132 16.2 DigestAuthenticationFilter 133 16.2.1配置 135 17.记住我的身份验证 136 17.1概述 136 17.2简单的基于哈希的令牌方法 136 17.3持久性令牌方法 137 17.4记住我的接口和实现 138 17.4.1 TokenBasedRememberMeServices 138 17.4.2 PersistentTokenBasedRememberMeServices 139 18.跨站点请求伪造(CSRF) 140 18.1 CSRF攻击 140 18.2同步器令牌模式 141 18.3何时使用CSRF保护 142 18.3.1 CSRF保护和JSON 142 18.3.2 CSRF和无状态浏览器应用程序 143 18.4使用Spring Security CSRF保护 143 18.4.1使用适当的HTTP动词 144 18.4.2配置CSRF保护 144 18.4.3包含CSRF令牌 145 表单提交 145 Ajax和JSON请求 145 CookieCsrfTokenRepository 146 18.5 CSRF警告 147 18.5.1超时 148 18.5.2登录 148 18.5.3注销 149 18.5.4多部分(文件上传) 149 在Spring Security之前放置MultipartFilter 150 包含CSRF令牌 151 18.5.5隐藏的HttpMethodFilter 151 18.6覆盖默认值 151 19. CORS 152 20.安全性HTTP响应头 154 20.1默认的安全头 154 20.1.1缓存控制 157 20.1.2内容类型选项 158 20.1.3 HTTP严格传输安全(HSTS) 159 20.1.4 HTTP公钥密码(HPKP) 161 20.1.5 X-Frame-Options 163 20.1.6 X-XSS保护 164 20.1.7内容安全策略(CSP) 165 配置内容安全策略 166 其他资源 168 20.1.8推荐人政策 168 配置引用者策略 169 20.2自定义标题 169 20.2.1静态头 169 20.2.2标题作者 170 20.2.3 DelegatingRequestMatcherHeaderWriter 171 21.会议管理 172 21.1 SessionManagementFilter 173 21.2 SessionAuthenticationStrategy 173 21.3并发控制 174 21.3.1查询当前通过身份验证的用户及其会话的SessionRegistry 176 22.匿名身份验证 177 22.1概述 177 22.2配置 178 22.3 AuthenticationTrustResolver 179 23. WebSocket安全 180 23.1 WebSocket配置 181 23.2 WebSocket身份验证 182 23.3 WebSocket授权 182 23.3.1 WebSocket授权说明 183 消息类型的WebSocket授权 184 目的地上的WebSocket授权 184 23.3.2出站消息 185 23.4执行相同的来源政策 185 23.4.1为什么同源? 185 23.4.2 Spring WebSocket允许的来源 186 23.4.3添加CSRF到Stomp头 186 23.4.4在WebSockets中禁用CSRF 187 23.5使用SockJS 187 23.5.1 SockJS和框架选项 187 23.5.2轻松放松CSRF 188 第五部分授权 190 24.授权体系结构 190 24.1当局 190 24.2预调用处理 191 24.2.1 AccessDecisionManager 191 24.2.2基于投票的AccessDecisionManager实现 192 RoleVoter 193 AuthenticatedVoter 194 自定义选民 194 24.3调用处理后 194 24.4分层角色 196 25.安全的对象实现 197 25.1 AOP联盟(MethodInvocation)安全拦截器 197 25.1.1显式MethodSecurityInterceptor配置 197 25.2 AspectJ(JoinPoint)安全拦截器 198 26.基于表达式的访问控制 200 26.1概述 200 26.1.1通用内置表达式 201 26.2网络安全表达式 202 26.2.1在Web安全表达式中引用Bean 203 26.2.2 Web安全表达式中的路径变量 204 26.3方法安全表达式 204 26.3.1 @Pre和@Post注释 205 访问控制使用@PreAuthorize和@PostAuthorize 205 使用@PreFilter和@PostFilter进行过滤 207 26.3.2内置表达式 207 PermissionEvaluator接口 208 方法安全元注释 209 第六部分 其他主题 209 27.域对象安全(ACL) 209 27.1概述 209 27.2重要概念 211 27.3入门 214 28.预认证方案 216 28.1预认证框架类 216 28.1.1 AbstractPreAuthenticatedProcessingFilter 217 J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 217 28.1.2 PreAuthenticatedAuthenticationProvider 218 28.1.3 Http403ForbiddenEntryPoint 218 28.2具体实施 219 28.2.1请求头认证(Siteminder) 219 Siteminder示例配置 219 28.2.2 Java EE容器认证 220 29. LDAP认证 220 29.1概述 220 29.2在Spring Security中使用LDAP 221 29.3配置LDAP服务器 221 29.3.1使用嵌入式测试服务器 222 29.3.2使用绑定认证 222 29.3.3加载权限 223 29.4实现类 223 29.4.1 LdapAuthenticator实现 224 通用功能 224 认证者 225 PasswordComparisonAuthenticator 225 29.4.2连接到LDAP服务器 225 29.4.3 LDAP搜索对象 225 FilterBasedLdapUserSearch中 225 29.4.4 LdapAuthoritiesPopulator 226 29.4.5 Spring Bean配置 226 29.4.6 LDAP属性和定制的UserDetails 227 29.5 Active Directory认证 228 29.5.1 ActiveDirectoryLdapAuthenticationProvider 228 活动目录错误代码 229 30. JSP标签库 230 30.1声明Taglib 230 30.2授权标签 230 30.2.1禁用测试的标签授权 231 30.3认证标签 232 30.4 accesscontrollist标签 232 30.5 csrfInput标签 233 30.6 csrfMetaTags标签 233 31 Java认证和授权服务(JAAS)提供者 235 31.1概述 235 31.2摘要:Java认证提供者 235 31.2.1 JAAS CallbackHandler 235 31.2.2 JAAS权威机构 236 31.3 DefaultJaasAuthenticationProvider 237 31.3.1 InMemoryConfiguration 237 31.3.2 DefaultJaasAuthenticationProvider示例配置 238 31.4 JaasAuthenticationProvider 239 31.5作为主题运行 240 32. CAS认证 240 32.1概述 240 32.2 CAS的工作原理 240 32.2.1 Spring安全和CAS交互序列 241 32.3 CAS客户端的配置 244 32.3.1服务票据认证 244 32.3.2单一注销 246 32.3.3使用CAS认证无状态服务 249 配置CAS以获取代理授予票证 249 使用代理票证调用无状态服务 250 32.3.4代理票证认证 251 33. X.509认证 253 33.1概述 253 33.2将X.509身份验证添加到您的Web应用程序 253 33.3在Tomcat中设置SSL 254 34.运行认证替换 255 34.1概述 255 34.2配置 255 35. Spring Security加密模块 257 35.1简介 257 35.2加密器 257 35.2.1 BytesEncryptor 257 35.2.2 TextEncryptor 258 35.3关键发电机 258 35.3.1 BytesKeyGenerator 258 35.3.2 StringKeyGenerator 259 35.4密码编码 259 36.并发支持 260 36.1 DelegatingSecurityContextRunnable 260 36.2 DelegatingSecurityContextExecutor 262 36.3 Spring安全性并发类 264 37. Spring MVC集成 265 37.1 @EnableWebMvcSecurity 265 37.2 MvcRequestMatcher 265 37.3 @AuthenticationPrincipal 268 37.4 Spring MVC异步集成 271 37.5 Spring MVC和CSRF集成 271 37.5.1自动令牌包含 271 37.5.2解析CsrfToken 272 第七部分 Spring数据集成 273 38. Spring Data&Spring安全配置 273 39. @Query中的安全表达式 273 第八部分 附录 274 40.安全数据库模式 274 40.1用户模式 274 40.1.1集团当局 274 40.2持久登录(记得我)架构 275 40.3 ACL模式 275 40.3.1 HyperSQL 276 40.3.2 PostgreSQL 277 40.3.3 MySQL和MariaDB 278 40.3.4 Microsoft SQL Server 279 40.3.5 Oracle数据库 280 41.安全命名空间 282 41.1 Web应用程序安全性 282 41.1.1 282 41.1.2 282 属性 283 的子元素 285 41.1.3 286 的父元素 286 属性 286 41.1.4 286 属性 287 父元素 287 41.1.5 <headers> 287 <headers>属性 288 <headers>的父元素 288 <headers>的子元素 288 41.1.6 289 属性 289 的父元素 289 41.1.7 289 属性 289 的父元素 290 41.1.8 290 属性 290 的父元素 290 41.1.9 290 的子元素 290 41.1.10 291 属性 291 的父元素 291 41.1.11 291 属性 291 的父元素 291 41.1.12 291 属性 292 的父元素 292 41.1.13 <frame-options> 292 <frame-options>属性 292 <frame-options>的父元素 293 41.1.14 [removed] 293 [removed]属性 293 [removed]的父元素 294 41.1.15 294 属性 294 的父元素 294 41.1.16 <header> 294 <header-attributes>属性 294 <header>的父元素 295 41.1.17 295 的父元素 295 属性 295 41.1.18 295 父元素 296 属性 296 41.1.19 296 的父元素 296 属性 296 41.1.20 <expression-handler> 297 <expression-handler>的父元素 297 属性 297 41.1.21 <form-login> 297 <form-login>的父元素 298 <form-login>属性 298 41.1.22 299 的父元素 300 属性 300 41.1.23 元素 300 属性 300 41.1.24 300 的父元素 300 属性 301 41.1.25 302 的父元素 302 属性 302 41.1.26 302 父元素 302 属性 303 41.1.27 303 的父元素 303 属性 303 的子元素 305 41.1.28 305 的父元素 305 属性 305 的子元素 305 41.1.29 306 的父元素 306 属性 306 41.1.30 306 的父元素 306 的子元素 307 41.1.31 307 的父元素 307 属性 307 41.1.32 307 的父元素 307 属性 307 41.1.33 元素 309 的父元素 309 属性 309 41.1.34 309 的父元素 309 属性 309 的子元素 310 41.1.35 311 的父元素 311 属性 311 41.1.36 312 的父元素 312 属性 312 41.1.37 313 属性 313 的子元素 313 41.1.38 313 的父元素 313 属性 313 41.1.39 314 属性 314 的子元素 314 41.2 WebSocket安全 314 41.2.1 315 属性 315 的子元素 316 41.2.2 316 的父元素 316 属性 316 41.3认证服务 317 41.3.1 317 属性 317 的子元素 317 41.3.2 318 的父元素 318 属性 318 的子元素 318 41.3.3 319 属性 319 41.3.4 320 的父元素 320 属性 320 的子元素 320 41.3.5 320 的父元素 321 属性 321 41.3.6 321 属性 321 的子元素 321 41.3.7 321 的父元素 322 属性 322 41.4方法安全 322 41.4.1 322 属性 322 的子元素 324 41.4.2 324 的父元素 324 属性 324 41.4.3 324 的父元素 325 325 41.4.4 325 的父元素 325 属性 325 41.4.5 325 的父元素 325 属性 325 41.4.6 326 的父元素 326 属性 326 41.4.7使用安全方法 326 父节点 326 属性 326 41.4.8 326 属性 327 的子元素 327 41.4.9 327 属性 327 的子元素 327 41.4.10 327 父元素 328 属性 328 41.5 LDAP名称空间选项 328 41.5.1使用。定义LDAP服务器 328 属性 329 41.5.2 329 的父元素 329 属性 329 的子元素 331 41.5.3 331 的父元素 331 属性 332 的子元素 332 41.5.4 332 属性 332 42.春季安全依赖 333 42.1 spring-security-core 334 42.2 spring-security-remoting 334 42.3 spring-security-web 335 42.4 spring-security-ldap 335 42.5 spring-security-config 336 42.6 spring-security-acl 336 42.7 spring-security-cas 337 42.8 spring-security-openid 337 42.9 spring-security-taglibs 338 43.代理服务器配置 338 44. Spring Security FAQ 339 44.1一般问题 339 44.1.1 Spring Security是否会处理我所有的应用程序安全要求? 339 44.1.2为什么不使用web.xml安全? 339 44.1.3需要哪些Java和Spring Framework版本? 341 44.1.4我是Spring Security的新手,我需要构建一个支持通过HTTPS进行CAS单点登录的应用程序,同时允许对某些URL进行本地基本身份验证,并对多个后端用户信息源(LDAP和JDBC)进行身份验证。我已经复制了一些我发现的配置文件,但不起作用。什么可能是错的? 341 44.2常见问题 342 44.2.1当我尝试登录时,我收到一条错误消息,指出“Bad Credentials”。怎么了? 343 44.2.2当我尝试登录时,我的应用程序进入“无限循环”,发生了什么事? 344 44.2.3我收到一条异常消息“访问被拒绝(用户是匿名的)”。怎么了? 344 44.2.4即使在我退出应用程序之后,为什么还能看到安全的页面? 345 44.2.5我得到一个异常,消息“在SecurityContext中没有找到认证对象”。怎么了? 345 44.2.6我无法使LDAP认证正常工作。我的配置有什么问题? 345 44.2.7会话管理 346 44.2.8我使用Spring Security的并发会话控制来防止用户一次登录多次。登录后打开另一个浏览器窗口时,不会阻止我再次登录。为什么我可以多次登录? 347 44.2.9为什么在通过Spring Security进行身份验证时会话ID发生了变化? 347 44.2.10我正在使用Tomcat(或其他一些servlet容器),并为我的登录页面启用了HTTPS,之后切换回HTTP。这是行不通的 - 我只是在认证之后回到登录页面。 347 44.2.11我没有在HTTP和HTTPS之间切换,但是我的会话仍然丢失 348 44.2.12我试图使用并发会话控制支持,但是不会让我重新登录,即使我确定我已经注销并且没有超出允许的会话。 348 44.2.13 Spring Security正在创建一个会话,即使我已经配置了它,通过设置create-session属性为永远不会。 348 44.2.14执行POST时,我得到了一个403 Forbidden 349 44.2.15我正在使用RequestDispatcher将请求转发到另一个URL,但是我的安全限制没有被应用。 349 44.2.16我已经将Spring Security的元素添加到我的应用程序上下文中,但是如果将安全注释添加到我的Spring MVC控制器bean(Struts操作等)中,那么它们似乎没有效果。 349 44.2.17我有一个肯定被认证的用户,但是当我在一些请求期间尝试访问SecurityContextHolder时,认证是空的。为什么我看不到用户信息? 350 44.2.18在使用URL属性时,授权JSP标记不尊重我的方法安全注释。 350 44.3 Spring安全体系结构问题 350 44.3.1我如何知道X是哪个包? 350 44.3.2名称空间元素如何映射到传统的bean配置? 351 44.3.3“ROLE_”是什么意思,为什么我的角色名字需要它? 351 44.3.4如何知道添加到我的应用程序中的哪些依赖关系与Spring Security一起使用? 352 44.3.5运行嵌入式ApacheDS LDAP服务器需要哪些依赖关系? 352 44.3.6什么是UserDetailsService,我需要一个吗? 353 44.4共同的“Howto”请求 353 44.4.1我需要登录更多的信息,而不仅仅是用户名。如何添加对额外登录字段(例如公司名称)的支持? 354 44.4.2如果只有所请求的URL的片段值不同(例如/ foo#bar和/ foo#blah),我该如何应用不同的拦截url链接? 354 44.4.3如何在UserDetailsService中访问用户的IP地址(或其他Web请求数据)? 354 44.4.4如何从UserDetailsService访问HttpSession? 355 44.4.5如何在UserDetailsService中访问用户的密码? 355 44.4.6如何动态定义应用程序中的安全URL? 355 44.4.7如何针对LDAP进行身份验证,但从数据库加载用户角色? 357 44.4.8我想修改由命名空间创建的bean的属性,但是模式中没有任何东西支持它。我可以做什么放弃命名空间的使用? 358 45.从3.x迁移到4.x 359

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值