(1)spring security - 项目环境搭建及入门
目录
- 1.前提条件说明
- 2.项目搭建
- 2.1.创建父工程
- 2.2.创建子模块`userManagement`
- 2.3.编写测试接口
- 3.Spring Security的默认配置
- 3.1.运行程序
- 3.2.部署到其它机器运行
- 3.2.1.单独打包模块
- 4.Spring Security是如何工作的?
- 4.1.默认的SecurityFilterChain
- 5.入门
- 5.1.自定义用户名和密码
- 5.2.什么是认证、授权和访问控制?
- 5.3.认证流程
- 6.单元测试
- 7.小结
本章目标:
- 了解Spring Security的默认配置
- 了解Spring Security的基本架构
1.前提条件说明
- spring boot :3.2.11
- maven :apache-maven-3.9.5
- jdk : redhat-jdk-17_0_13
2.项目搭建
一个父工程,里面包含多个模块。每个模块都可以单独的启动类,可以单独部署。这个项目将基于springMVC构建不同的RESTful API,实现前后端分离,前端将使用Vue3搭建。
2.1.创建父工程
父工程的pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 注意:父工程的打包方式必须式:pom -->
<packaging>pom</packaging>
<groupId>com.drson</groupId>
<artifactId>IPMS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>工业园管理系统</description>
<properties>
<!-- 使用的spring boot版本 -->
<spring.boot.version>3.2.11</spring.boot.version>
</properties>
<!-- 项目的模块 -->
<modules>
<module>userManagement</module><!-- 用户管理模块 -->
</modules>
<!-- 依赖管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 所有模块都需要的依赖项 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2.创建子模块userManagement
子模块的pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 继承父工程 -->
<parent>
<groupId>com.drson</groupId>
<artifactId>IPMS</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<!-- 模块的打包方式为:jar -->
<packaging>jar</packaging>
<artifactId>userManagement</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>userManagement</name>
<description>用户管理模块</description>
<properties>
</properties>
<!-- 模块的依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<!-- 配置需要使用的插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<mainClass>com.drson.usermanagement.UserManagementApplication</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
2.3.编写测试接口
TestController.java
package com.drson.usermanagement.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/test")
public String test(){
return "test";
}
}
3.Spring Security的默认配置
在Spring boot应用程序中,我们只需要包含Spring-boot-starter-security依赖项,Spring boot就会自动配置Spring Security,并在WebSecurityConfiguration类中定义合理的默认值。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默认情况下,Spring Security自动配置如下:
- 创建一个名为springSecurityFilterChain的bean。为每个请求用一个名为springSecurityFilterChain的bean在Servlet容器中注册过滤器。
- 用于对使用远程协议和web服务发出的请求进行身份验证的HTTP基本身份验证。
- 生成默认登录表单。
- 创建一个用户,用户名为user,密码输出到控制台。
- 密码使用BCrypt加密
- 启用登出功能。
- 集成Servlet API,通过标准Servlet API(如HttpServletRequest.isUserInRole()和HttpServletRequest.getUserPrincipal())访问安全信息。
- 其他功能,如防止CSRF攻击,会话固定和点击劫持。
3.1.运行程序
在浏览器中输入地址http://localhost:8080/test,将会跳转到登录页面,输入用户名:user,以及上图的密码(密码是随机的,每次启动运行都会生成不一样的密码)。
身份验证成功后,将会跳转回http://localhost:8080/test
3.2.部署到其它机器运行
我局域网内有一台ARM机器,现在就演示如何在这个机器上运行上面的程序:
我的机器的系统系统环境:
Linux TVI3315A 6.6.60-current-rockchip64 #1 SMP PREEMPT Fri Nov 8 15:28:28 UTC 2024 aarch64 aarch64 aarch64 GNU/Linuxjdk版本:
root@TVI3315A:~# java --version openjdk 17.0.13 2024-10-15 OpenJDK Runtime Environment (build 17.0.13+11-Ubuntu-2ubuntu120.04) OpenJDK 64-Bit Server VM (build 17.0.13+11-Ubuntu-2ubuntu120.04, mixed mode, sharing)
3.2.1.单独打包模块
按照上图操作,将生成的jar包上传到服务器(拥有jdk或jre环境的机器),使用以下命令:
java -jar userManagement-0.0.1-SNAPSHOT.jar
运行界面如下:
最后,使用浏览器登录,验证效果。地址为服务器的地址:http://192.168.124.7:8080/test
,将跳转到登录界面,要求你输入用户名和密码。
4.Spring Security是如何工作的?
开发SpringMVC应用程序时,Spring Security是基于servlet过滤器的。过滤器的核心任务是在将请求发送到Servlet以进行实际请求处理时对某些操作进行预处理和后处理。
如下图所示,基本的工作流程:
当发送请求时,容器根据请求URI的路径创建一个FilterChain,其中包含所有过滤器实例和应该处理HttpServletRequest的Servlet。在Spring中,请求处理程序servlet总是DispatcherServlet。
Spring提供了一个名为DelegatingFilterProxy的过滤器实现,它允许在Servlet容器的生命周期和Spring的ApplicationContext之间进行桥接。
在Spring Boot应用程序中,SecurityFilterAutoConfiguration会自动注册名为springSecurityFilterChain的DelegatingFilterProxy过滤器。
一旦请求到达DelegatingFilterProxy, Spring将处理委托给FilterChainProxy bean,该bean利用SecurityFilterChain执行要为当前请求调用的所有过滤器的列表。
一旦请求到达SecurityFilterChain中已注册的过滤器,相应的过滤器将请求委托给其他bean执行相应的任务。例如,AuthenticationProcessingFilter准备身份验证实例,并将其委托给AuthenticationManager进行身份验证流。
4.1.默认的SecurityFilterChain
我们从运行userManagement-0.0.1-SNAPSHOT.jar
程序的界面可以看到Spring Security默认配置中使用了哪些过滤器:
- DisableEncodeUrlFilter:禁用Spring Security对URL的自动编码。在某些情况下,用户可能希望禁用Spring Security对URL的自动编码,例如在特定的代理服务器或反向代理服务器上,这些代理服务器可能会自己处理URL的编码。此时,就需要使用DisableEncodeUrlFilter来禁用Spring Security对URL的编码。
- WebAsyncManagerIntegrationFilter:主要作用是将SecurityContext与Spring Web中用于处理异步请求的WebAsyncManager进行集成。它确保在异步处理过程中,安全上下文(SecurityContext)能够从调用者线程传播到被调用者线程,从而在异步任务中能够正确获取用户认证信息和其他安全上下文信息。
- SecurityContextHolderFilter:作用主要是负责安全上下文的持久化工作。它通过将安全上下文(SecurityContext对象)保存为当前用户HttpSession对象的一个属性,从而在跨请求时保持安全上下文。这样,即使在多个请求之间,用户的安全信息也能被正确地保存和恢复。
- HeaderWriterFilter:HeaderWriterFilter的主要作用是在HTTP响应的头部添加特定的安全标头,以增强Web应用程序的安全性。这些安全标头包括X-Frame-Options、X-XSS-Protection和X-Content-Type-Options等,有助于防止点击劫持、跨站脚本攻击(XSS)和MIME类型混淆等安全威胁。
- CsrfFilter:CsrfFilter的主要作用是防御CSRF攻击。CSRF(Cross-Site Request Forgery,跨站请求伪造)是一种网络攻击手段,攻击者通过利用用户的登录状态,诱导用户浏览器发送恶意请求,从而执行非用户本意的操作,如转账、发送邮件等。
- LogoutFilter:在Spring Security中的作用主要是处理用户的注销请求,并执行相应的注销逻辑。当用户发起注销请求时,LogoutFilter会拦截该请求,并执行以下操作:
- 使当前会话失效:通常通过使会话无效或删除会话来实现,以确保用户注销后无法再使用该会话
- 清除安全上下文:删除与安全上下文相关的所有信息,如当前认证的用户、权限等
- 重定向:将用户重定向到指定的注销成功页面或登录页面
- UsernamePasswordAuthenticationFilter:作用是处理基于用户名和密码的认证逻辑。它是Spring Security中一个关键的过滤器,负责实现最常见的基于表单的登录认证机制。
- DefaultLoginPageGeneratingFilter:作用是生成默认的登录页面。 当在安全配置中没有指定登录页面时,Spring Security会自动使用这个过滤器来生成一个默认的登录页面,供用户进行登录操作。
- DefaultLogoutPageGeneratingFilter:用于在用户登出时生成一个默认的登出页面。当用户执行登出操作时,这个过滤器会拦截请求,生成一个包含登出确认信息的页面,并显示给用户。这样,用户可以确认是否真的要登出系统,从而提供更好的用户体验和安全性。
- BasicAuthenticationFilter:负责处理出现在HTTP头中的基本身份验证凭据。这些凭据通常是用户名和密码,经过Base64编码后放在HTTP请求头中传递。
- RequestCacheAwareFilter:主要作用是在用户登录成功后,重新恢复因为登录被打断的请求。当用户访问受保护的资源时,如果尚未登录,Spring Security会拦截该请求并重定向到登录页面。在重定向之前,Spring Security会将当前请求的信息缓存起来,以便在用户登录成功后恢复该请求。这有助于提升用户体验,使用户在登录后能够无缝地继续之前的操作。
- SecurityContextHolderAwareRequestFilter:主要作用是使HttpServletRequestWrapper能够感知SecurityContextHolder中的安全上下文信息。通过这种方式,过滤器能够包装HttpServletRequest对象,使其具备访问SecurityContextHolder中安全上下文的能力,从而使得接口HttpServletRequest上定义的安全相关方法(如getUserPrincipal)能够访问到相应的安全信息。
- AnonymousAuthenticationFilter:作用是为那些没有经过身份认证的用户分配一个匿名身份。这种身份通常具有较低的权限,使其能够正常访问公开的资源,而不会引发异常或错误。
- ExceptionTranslationFilter:作用是处理认证和授权过程中的异常。它是一个关键的组件,用于捕获并处理特定的Spring Security异常,如AuthenticationException和AccessDeniedException。
- AuthorizationFilter:主要作用是进行访问控制,确保用户有权访问特定的资源。
5.入门
下面我们开始尝试定义自己的spring security配置。
5.1.自定义用户名和密码
首先,我需要编写自己的配置文件,如下:
package com.drson.usermanagement.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
/*
* @EnableWebSecurity注解在Spring Security中的作用主要包括以下几个方面:
* 1.启用Web安全支持:@EnableWebSecurity注解用于启用Spring Security的Web安全支持。它会自动导入WebSecurityConfiguration,这是Spring Security的核心配置,会设置一些默认的安全配置,例如默认的登录页面、登出行为和Session管理策略等。
* 2.自定义HTTP安全配置:通过覆盖configure(HttpSecurity http)方法,可以自定义HTTP安全配置,例如定义哪些URL路径应该被保护、使用哪些认证方法等
* 3.启用Web安全功能:@EnableWebSecurity注解会配置SpringWebMvcImportSelector,从而导入SpringWebMvcConfigurer,这个配置器结合Spring MVC使用,提供基本的Web安全集成
* 4.注册过滤器链:添加FilterChainProxy到springSecurityFilterChain,这是一个特殊的过滤器链,包含了一系列用于保护应用的标准过滤器
* 5.设置身份验证管理器:配置全局的AuthenticationManager,可以通过覆盖configure(AuthenticationManagerBuilder auth)方法来自定义用户的认证机制,例如使用内存中的用户、数据库中的用户或LDAP服务器
* 6.启用方法级别的安全性:允许使用注解(如@PreAuthorize、@PostAuthorize、@Secured等)来控制方法的访问权限
* 7.发布安全事件:Spring Security会发布各种安全事件,@EnableWebSecurity注解确保这些事件可以被监听和处理
*
* 这些功能使得@EnableWebSecurity注解在Spring Security中扮演了非常重要的角色,帮助开发者轻松地实现和配置Web安全功能。
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
//重新配置密码
@Bean
public UserDetailsService userDetailsService(){
/*
* InMemoryUserDetailsManager是Spring Security内置的一个实现UserDetailsManager接口的默认配置实现,
* 主要用于从配置文件中加载用户的账户信息。它主要用于开发调试环境,通常用于测试和功能演示,一般不推荐在生产环境中使用。
* InMemoryUserDetailsManager在内存中注册用户,而不需要持久化存储。
*/
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(
User.withUsername("admin")
.password(new BCryptPasswordEncoder().encode("123456"))
.build()
);
return manager;
}
//定义密码编码器
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
这将覆盖默认的配置。在登录页面输入用户名:admin,密码:123456,可以成功登录。
5.2.什么是认证、授权和访问控制?
-
Authentication(认证、身份验证):身份验证是根据其声称的身份,验证主体身份的过程。主体可以是尝试访问应用程序的任何人,例如用户、另一个程序或API等。访问受保护的应用程序时,主体必须提供其身份的证据,通常是用户名和密码组合。如果主体是另一个程序,则通过匹配提供的API密钥和密码来确认身份。
-
Authorization(授权):授权是指向经过身份验证的主体授予权限(通常是角色)并允许访问特定的安全资源的过程。授权总是在认证过程之后执行。
-
访问控制是指在将资源的访问属性与用户授予的权限进行比较后,通过决定是否允许用户访问资源来控制对资源的访问。
5.3.认证流程
下面的图片显示了认真流程是如何在高层次上发生的:
具体的流程学习,将在后面发布的系列文章中发布。
6.单元测试
需要添加如下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
编写测试代码:
package com.drson.usermanagement;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
/*
* @AutoConfigureMockMvc注解在Spring Boot测试中用于自动配置MockMvc对象,
* 主要用于模拟MVC请求和响应。通过使用这个注解,可以方便地测试控制器的行为和结果,而不需要启动整个服务器。
*
* addFilters = false的作用是防止在测试过程中应用过滤器。
* 在集成测试中,如果不设置addFilters = false,测试请求可能会经过过滤器链,
* 导致需要登录或其他认证步骤,这可能会使测试失败。通过设置addFilters = false,
* 可以避免这些过滤器的影响,使得测试更加简单和直接
*/
@SpringBootTest
//@AutoConfigureMockMvc(addFilters = false) //或者直接禁用过滤器,禁用认证流程
@AutoConfigureMockMvc
class UserManagementApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(username = "admin",password = "123456")//用户名和密码
public void testTestController() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/test"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("test"));
}
}
测试通过:
7.小结
本章首先搭建了一个项目环境,为以后学习spring相关知识提供一个基础环境。
然后,简单了解了spring security的一些默认配置,尝试修改的默认用户名和密码,完成了简单的单元测试。
后续将一步一步学习spring security这个框架,慢慢完成用户管理的功能模块。