什么是 Spring Security
Spring Security文档
Spring Security中文文档
Spring Security 是 Spring 家族中的安全型开发框架,主要解决三大方面问题:认证(你是谁)、授权(你能干什么)、常见攻击保护(CSRF、HTTP安全响应头设置、Http防火墙)。它常用于 Spring Boot 及 Spring Cloud 框架中。总体架构核心非常简单,在国内大部分使用其Servlet应用的功能,其就在Filter一点上扩展,但学习来优点复杂,因为安全考虑的方面太多、应用场景也多,所以集成的功能也挺多,不过它提供了一个综合的解决方案,后面的 Spring Authorization Server 也是在 Security 基础上构建的,所以也是必学内容。
示例
下面通过一个例子来简单测试下:
首先在 idea 中新建 Spring Initializr 应用,环境如下:
JDK 17
Spring Boot 3.2.2
Maven 3.8.8
加入 Spring Security 包,完整的 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.2.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.alex</groupId><artifactId>security-01-hello</artifactId><version>0.0.1-SNAPSHOT</version><name>security-01-hello</name><description>security-01-hello</description><properties><java.version>17</java.version></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><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.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
新建一个 HelloController:
package com.alex.security01hello;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@GetMapping("hello")private String hello() {return "Hello, Spring Security!";}
}
运行程序
然后运行启动程序,这里是:Security01HelloApplication main
此时通过浏览器访问: http://127.0.0.1:8080/hello,页面会被重定向到 http://127.0.0.1:8080/login,此时查看 idea 的 Console ,会有生成的密码:
在 login 页面,输入 user 及上面的密码,就可以访问到 hello api 输出的内容。
背后原理
Spring Security 还挺复杂,当在运行上面程序的时候,其在背后执行了很多个步骤,可以参考官方文档:
这里根据官方文档,可以固定一个 用户名、密码及角色,避免再查看控制台的复杂密码:
@EnableWebSecurity
@Configuration
public class DefaultSecurityConfig {@Bean@ConditionalOnMissingBean(UserDetailsService.class)InMemoryUserDetailsManager inMemoryUserDetailsManager() {UserDetails user = org.springframework.security.core.userdetails.User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();return new InMemoryUserDetailsManager(user);}@Bean@ConditionalOnMissingBean(AuthenticationEventPublisher.class)public DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher() {return new DefaultAuthenticationEventPublisher();}
}
再次重启程序,如果被重定向到登录页,直接输入 user+password 即可登录。
下面通过配置日志,查看 Spring Security 在请求时做了啥,首先在 resources/application.properties 配置 Spring Security 日志:
application.properties:
logging.level.org.springframework.security=TRACE
然后配置 logback 日志,在 resources下添加 logback.xml:
<configuration><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><root level="WARN"><appender-ref ref="STDOUT" /></root></configuration>
重启程序,在浏览器中输入:127.0.0.1:8080/hello,观察控制台会输出相关日志:
通过上面可以看出,在访问的时候,一个 Filter 链中包含了16个 Filter, 最终因为在 AuthorizationFilter 的 doFilter 方法中抛出 AccessDeniedException 异常,并且重定向到 login 页面:
我们访问的 login 页面是在 DefaultLoginPageGeneratingFilter 中生成的:
参考:自定义登录页