基本原理

本节先展示一下 Security 的默认安全登录方式,让读者快速直观地认识 Security。然后,分析 Security 的基本原理,以及部分源码,为进一步学习打下基础。

默认安全登录

首先,在项目中引入依赖。

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

为了启动 Spring Security,需要将 it-security-demo 中的配置项在配置文件中注释掉,这是为了启动项目方便,不需要每次输入密码。现在启动 Spring Security,将配置项在 application.properties 中注释,如下。

#security.basic.enabled = false

此时启动项目,就会启动 Security,这样可以看到在控制台上展示密码生成日志,如图9.1所示。

image 2024 03 31 23 37 01 433
Figure 1. 图9.1 密码生成日志

多次启动后,会发现图中的密码每次都不同,这是因为 Security 的密码是随机生成的。我们随意访问一个 RESTful API,会自动跳出一个登录对话框,这也是 Security 内部的默认跳转。图9.2是系统默认的登录对话框,以及登录成功后的效果(验证后会跳转到图9.2下方地址栏中的地址)。

image 2024 03 31 23 37 41 203
Figure 2. 图9.2 默认登录对话框及登录成功后的效果

既然密码每次是随机的,那么用户名呢?在 Spring Security 中,用户名也被固定了,只能是 user。

目前为止,我们已经成功启动 Spring Security,并且登录进系统。但这不是我们想要的效果,其中暴露了很多问题,下面列举部分不足。

  • 密码随机生成。用户也不知道自己的密码,系统将不能登录。

  • 登录用户唯一。当用户申请使用系统后,每个用户都有自己的账号。没有唯一的密码。

  • 登录页面是以弹框的方式打开,不是自定义的首页。系统没有自定义首页。

  • 缺少多种登录方式,例如以第三方的方式登录。

对于这些问题,Spring Security 并不是不能解决,因为 Security 允许开发者根据自己的情况开发扩展,实现接口。上文列举的部分不足,我们将会在本章的后续章节一一解决。

Security原理说明

Spring Security 最核心的其实是过滤器链,一组 Filter。所有发送的请求都会经过过滤器链,同样响应也会经过过滤器链,在系统启动时 Spring Boot 会自动地把它们配置进去。

基本原理图

下面是 Security 的原理图,如图9.3所示。

image 2024 03 31 23 39 42 331
Figure 3. 图9.3 Security的原理图

上面的图是一个最常见的介绍 Security 的原理图,下面就分别说明它们的功能,以及整体的运行流程。

  • UsernamePasswordAuthenticationFilter:表单登录。

  • BasicAuthenticationFilter:HTTP登录。

  • … :这里还有很多过滤器,可以根据自己的情况加入过滤器。

  • ExceptionTranslationFilter:这个过滤器必须要在 FilterSecurityInterceptor 的前面,位置不能动,它的作用是处理 FilterSecurityInterceptor 抛出的异常。

  • FilterSecurityInterceptor:这个过滤器处于整个过滤器链的最后一环,也是进入 RESTful 程序的前一个程序,这里将会做最后一次验证。

整体流程

每个过滤器的作用都已经被说明了,下面将描述,从认证开始进入 RESTful API 的整个流程。

首先,用户输入用户名和密码,然后单击登录。其中绿色部分的每一种过滤器代表着一种认证方式,主要用于检查当前请求有没有涉及用户信息,如果当前没有,就会跳入到下一个绿色的过滤器中,请求成功会显示标记。绿色认证方式可以配置,比如短信认证、微信认证等。如果我们不配置 BasicAuthenticationFilter,那么它就不会生效。

FilterSecurityInterceptor 过滤器是最后一个,它会决定当前的请求可不可以访问 RESTful API,判断规则会放在这里面。当不通过时会把异常抛给前面的 ExceptionTranslationFilter过滤器。

ExceptionTranslationFilter 接收异常信息时,将跳转页面引导用户进行认证。橘黄色和蓝色的位置不可更改。当没有认证的 request 进入过滤器链时,首先进入 FilterSecurityInterceptor,判断当前是否进行了认证,如果没有认证则进入 ExceptionTranslationFilter,处理抛出的异常,然后跳转到认证页面。部分源码如下所示。

UsernamePasswordAuthenticationFilter.java
public Authentication attemptAuthentication(HttpServletRequest request,
      HttpServletResponse response) throws AuthenticationException {
   if (postOnly && !request.getMethod().equals("POST")) {
      throw new AuthenticationServiceException(
          "Authentication method not supported:" +request.getMethod());
   }
   String username = obtainUsername(request);
   String password = obtainPassword(request);
   ……
}

这是表单过滤器,我们可以知道用户名与密码是从这里获取的,并封装返回 Authentication。Authentication 就是后续 Filter 决定页面跳转的依据。