一、Spring Security 核心概念
Spring Security 是一个强大的安全性框架,专注于身份验证(Authentication)和访问控制(Authorization)。其核心概念围绕以下几个方面展开:
1. 身份验证 (AUTHENTICATION)
身份验证是指确认用户的身份是否合法的过程。在 Spring Security 中,AuthenticationManager
负责处理用户的认证过程4。当用户尝试登录时,系统会检查用户名和密码或其他凭证的有效性。如果成功,则生成一个 Authentication
对象表示已认证的主体。
2. 授权 (AUTHORIZATION)
授权涉及决定某个经过身份验证的用户是否有权访问特定资源或执行某些操作。这一过程由 AccessDecisionManager
处理4。它根据预定义的安全规则评估用户的权限,并作出允许或拒绝的决策。
Spring Security 的基本原理
Spring Security 的运行机制依赖于一系列的核心组件和技术实现,主要包括以下几点:
1. 过滤器链 (FILTER CHAIN)
Spring Security 利用了 Servlet 规范中的过滤器机制,构建了一个复杂的过滤器链来拦截 HTTP 请求并应用相应的安全逻辑3。每个过滤器负责完成特定的任务,例如:
- 验证用户凭据 (
UsernamePasswordAuthenticationFilter
) - 记住我功能 (
RememberMeAuthenticationFilter
) - 登出支持 (
LogoutFilter
)
这些过滤器按照预定顺序依次调用,形成所谓的“责任链模式”,即每个过滤器可以决定是否将请求传递给下一个过滤器或者终止整个链条。
2. 责任链模式 (CHAIN OF RESPONSIBILITY PATTERN)
正如前面提到的,“责任链模式”是 Spring Security 架构的重要组成部分之一。这种设计模式允许多个对象有机会处理同一个请求,从而实现了模块化和灵活性。开发者可以通过自定义过滤器轻松扩展系统的功能。
3. 核心接口与类
以下是几个重要的接口/类及其作用:
AbstractSecurityInterceptor
: 所有安全拦截的基础抽象类,用于统一管理安全策略。AuthenticationProvider
: 实现具体的认证算法,比如基于数据库查询、LDAP 查询等。UserDetailsService
: 加载用户信息的服务接口,通常配合 JDBC 或其他数据源使用。GrantedAuthority
: 表示授予某角色的一组权限集合。
4. 配置选项
Spring Security 提供丰富的配置项以满足不同场景下的需求,包括但不限于:
- 用户名密码认证方式
- OAuth2/OIDC 支持
- CSRF 防护设置
- URL 匹配规则定义哪些路径需要保护以及如何保护它们
总结
综上所述,Spring Security 不仅具备完善的功能体系还具有很高的可定制程度。通过对过滤器链的设计运用职责链模式让整体架构既紧凑又灵活易于维护同时也方便二次开发适应各种复杂业务环境的要求
二、spring Security配置教程
笔者项目中使用的是Spring Security6.5
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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
2、 spring Security过滤配置笔者总结了两者方式第一种是通过代码方式来配置过滤权限验证
package com.example.util;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class WebSecurityConfigUtil {
@Bean
public SecurityFilterChain web(HttpSecurity http ) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll() // 允许访问的路径
.anyRequest().authenticated()
).formLogin(Customizer.withDefaults())//需要表单验证
.logout(logout -> logout.permitAll());
return http.build();
}
}
3、第二种方式是通过配置security-config.xml来过滤权限验证,security-config.xml配置放到如图1所示放到项目根目录下
图1
4、加载类
package com.example.util;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:security-config.xml")
public class WebSecurityConfig {
}
security-config.xml配置文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/public/**" access="permitAll()"/>
<security:form-login/>
<security:http-basic />
<security:logout/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="{noop}adminpass" authorities="ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
5、访问的ctronller
package com.example.login;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/public/hello")
public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
浏览器地址栏输入:http://localhost:8081/public/hello
出现以下界面说明配置成功