Spring-Security

Spring Security 整合 Firebase Authentication

1、概览 在现代 Web 应用中,用户身份认证和授权是至关重要的组成部分。从零开始构建身份认证层是一项具有挑战性的复杂任务。不过,随着基于云的身份认证服务的兴起,这一过程变得简单多了。 Firebase Authentication 就是这样一个例子,它是 Firebase 和谷歌 提供的一种完全托管的身份认证服务。 本文将带你了解如何将 Firebase Authentication 与 Spring Security 整合,以创建和认证我们的用户。我们要进行必要的配置,实现用户注册和登录功能,并创建一个自定义 Authentication Filter 来验证私有 API 端点的用户 Token。 2、项目设置 在实现之前,需要加入 SDK 依赖并正确配置应用。 2.1、依赖 首先,在项目的 pom.xml 文件中添加 Firebase admin 依赖: <dependency> <groupId>com.google.firebase</groupId> <artifactId>firebase-admin</artifactId> <version>9.3.0</version> </dependency> 该依赖提供了必要的类,用于在应用中与 Firebase Authentication 服务交互。 2.2、定义 Firebase 配置 Bean 现在,为了与 Firebase Authentication 交互,我们需要配置私钥(Private Key)来验证 API 请求。 在本例中,我们在 src/main/resources 目录下创建 private-key.json 文件。不过,在生产中,私钥应从环境变量中加载,或从 secret 管理系统中获取,以提高安全性。 使用 @Value 注解加载私钥,并用它来定义 Bean: @Value("classpath:/private-key.json") private Resource privateKey; @Bean public FirebaseApp firebaseApp() { InputStream credentials = new ByteArrayInputStream(privateKey.

删除 Spring Security 中的 ROLE_ 前缀

1、概览 在配置应用的安全设置时,用户的详细信息可能未包括 Spring Security 预期的 ROLE_ 前缀。这种情况下会导致 “Forbidden” 授权错误,无法访问受保护端点。 本文将带你了解如何配置 Spring Security,以允许使用不带 ROLE_ 前缀的角色。 2、Spring Security 默认行为 首先来看看 Spring Security 角色检查机制的默认行为。 添加一个 InMemoryUserDetailsManager,其中包含一个具有 ADMIN 角色的用户: @Configuration public class UserDetailsConfig { @Bean public InMemoryUserDetailsManager userDetailsService() { UserDetails admin = User.withUsername("admin") .password(encoder().encode("password")) .authorities(singletonList(new SimpleGrantedAuthority("ADMIN"))) .build(); return new InMemoryUserDetailsManager(admin); } @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } } 如上,创建 UserDetailsConfig 配置类,该类配置了一个 InMemoryUserDetailsManager Bean。在工厂方法内部,使用 PasswordEncoder 来处理用户详细信息的密码。 接着,添加要调用的端点: @RestController public class TestSecuredController { @GetMapping("/test-resource") public ResponseEntity<String> testAdmin() { return ResponseEntity.

Spring Security 6.3 中的新特性

1、简介 Spring Security 6.3 版在框架中引入了一系列安全增强功能。本文将带你了解其中一些最值得注意的特性,重点介绍它们的优点和用法。 2、被动式的 JDK 序列化支持 Spring Security 6.3 包含被动式的 JDK 序列化支持(Passive JDK Serialization Support),首先先来了解一下相关的问题和困扰。 2.1、Spring Security 的序列化设计 在 6.3 版本之前,Spring Security 对其类在不同版本之间通过 JDK Serialization 进行序列化和反序列化有严格的策略。这个限制是框架的一个有意设计决策,旨在确保安全性和稳定性。其理由是防止使用不同版本的Spring Security 反序列化在一个版本中序列化的对象时出现不兼容性和安全漏洞。 这一设计的一个关键方面是在整个 Spring Security 项目中使用全局 serialVersionUID。在 Java 中,序列化和反序列化过程使用唯一标识符 serialVersionUID 来验证加载的类是否与序列化对象完全一致。 通过为 Spring Security 的每个发布版本维护一个唯一的全局 serialVersionUID,该框架可确保一个版本的序列化对象无法使用另一个版本进行反序列化。这种方法有效地创建了一个版本屏障,防止了序列化版本 serialVersionUID 值不匹配的对象被反序列化。 例如,Spring Security 中的 SecurityContextImpl 类表示 Security Context 信息。该类的序列化版本包含该版本特有的 serialVersionUID。当尝试在不同版本的 Spring Security 中反序列化该对象时,serialVersionUID 不匹配会阻止该过程成功进行。 2.2、序列化设计带来的困扰 在优先增强安全性的同时,这种设计策略也带来了一些困扰。开发人员通常将 Spring Security 与 Spring Session 等其他 Spring 库集成,以管理用户登录会话(Session)。这些会话包含重要的用户身份认证和 Security Context 信息,通常通过 Spring Security 类实现。此外,为了优化用户体验并提高应用的可扩展性,开发人员通常会在各种持久存储解决方案(包括数据库)中存储这些会话数据。

Spring Security 检测密码是否泄露

1、概览 在构建处理敏感数据的 Web 应用时,确保用户密码的安全性非常重要。密码安全的一个重要方面是检查密码是否泄露,这通常是由于密码出现在 数据泄露事件 中。 Spring Security 6.3 引入了一项新功能,让我们可以轻松检查密码是否被已泄露。 本文将带你了解 Spring Security 中新的 CompromisedPasswordChecker API 以及如何将其集成到 Spring Boot 应用中。 2、密码泄露 密码泄露是指在数据泄露事件中暴露的密码,使其容易受到未经授权的访问。攻击者通常在凭证填充和密码填充攻击中使用这些泄露的密码,在多个网站上使用泄露的用户名-密码对,或在多个账户上使用通用密码。 要降低这种风险,关键是要在创建账户前检查用户密码是否泄露。 同样重要的是要注意,以前有效的密码可能会随着时间的推移而泄露,因此建议不仅在创建账户时,而且在登录过程中或任何允许用户更改密码的过程中都要检查密码是否泄露。如果登录尝试因检测到密码泄露而失败,可以提示用户重设密码。 3、CompromisedPasswordChecker Spring Security 提供了一个简单的 CompromisedPasswordChecker 接口,用于检查密码是否被泄露: public interface CompromisedPasswordChecker { CompromisedPasswordDecision check(String password); } 该接口只暴露了一个 check() 方法,该方法将密码作为输入,并返回一个 CompromisedPasswordDecision 的实例,表明密码是否已被破解/泄露。 check() 方法需要明文密码,因此必须在使用 PasswordEncoder 加密密码之前调用该方法。 3.1、配置 CompromisedPasswordChecker Bean 要在应用中启用密码泄露检查,需要声明 CompromisedPasswordChecker 类型的 Bean: @Bean public CompromisedPasswordChecker compromisedPasswordChecker() { return new HaveIBeenPwnedRestApiPasswordChecker(); } HaveIBeenPwnedRestApiPasswordChecker 是 Spring Security 提供的 CompromisedPasswordChecker 的默认实现。

Spring Security 6.3.0 发布

Spring Security 6.3.0 正式发布! 6.3 版本带来了几个引人注目的特性,如下: 长期的 JDK 序列化向后兼容性 新的方法安全注解和功能 密码受损检查 支持 OAuth 2.0 令牌交换 该版本将包含在即将发布的 Spring Boot 3.3 GA 版本中。 ⭐ 新特性 为 OAuth2AuthorizedClientId 添加 Getter #13648 为 JwtDecoders 添加超时默认值 #14890 文档:添加了将 GrantedAuthorityDefaults 声明为基础架构 Bean 的提示 #15065 改进全局身份认证(Global Authentication)的日志记录 #14711 文档小修正 #15043 需要对使用 Kotlin DSL 的导入进行微小的文档更新 #14969 OAuth2 客户端身份认证文档不完整 #14982 校对 CasAuthenticationFilter 文档 #14883 将 “Spring Boot 2.x” 替换为 “Spring Boot” #14919 简化禁用 “application/x-www-form-urlencoded” 编码 Client ID 和 Secret#14859 支持为依赖方注册元素指定标识符 #14487 更新 6.

Spring Boot 中 Spring Security 自动配置

1、概览 本文将带你了解 Spring Boot 中 Spring Security 的自动配置、默认安全配置,以及如何在需要时禁用或自定义它。 2、默认的 Spring Security 设置 首先添加 security starter 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 这包含初始/默认 Security 配置的 SecurityAutoConfiguration 类。 这里没有指定版本,因为项目使用了 spring-boot-starter-parent 作为 parent。 默认情况下,应用会启用身份验证,内容协商(Content Negotiation)用于确定应使用 basic 还是 formLogin。 有一些预定义的配置属性: spring.security.user.name= spring.security.user.password= 如果不使用预定义属性 spring.security.user.password 配置密码并启动应用,默认密码将随机生成并打印在控制台日志中: Using default security password: c8be15da-4489-4491-9dc6-fab3f91435c7 有关更多默认值,请参阅 Spring Boot 中文文档中的 属性配置。 3、禁用自动配置 要禁止 Security 自动配置并添加我们的自定义配置,需要排除 SecurityAutoConfiguration 自动配置类。 可以通过 @SpringBootApplication 注解中的 exclude 属性来实现: @SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) public class SpringBootSecurityApplication { public static void main(String[] args) { SpringApplication.

新版 Spring Security 中的路径匹配机制

Spring Security 是一个功能强大且可高度定制的安全框架,它提供了一套完整的解决方案,用于保护基于 Spring 的应用。在 Spring Security 中,路径匹配是权限控制的核心部分,它决定了哪些请求可以访问特定的资源。本文将带你详细了解 Spring Security 中的路径匹配策略,并提供相应的代码示例。 在旧版的 Spring Security 中,路径匹配方法有很多,但是新版 Spring Security 对这些方法进行了统一的封装,都是调用 requestMatchers 方法进行处理: public C requestMatchers(RequestMatcher... requestMatchers) { Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest"); return chainRequestMatchers(Arrays.asList(requestMatchers)); } requestMatchers 方法接收一个 RequestMatcher 类型的参数,RequestMatcher 是一个接口,这个接口是一个用来确定 HTTP 请求是否与给定的模式匹配的工具。这个接口提供了一种灵活的方式来定义请求的匹配规则,从而可以对不同的请求执行不同的安全策略。 所以在新版 Spring Security 中,不同的路径匹配分方案实际上就是不同的 RequestMatcher 的实现类。 1. AntPathRequestMatcher AntPathRequestMatcher 是 Spring 中最常用的请求匹配器之一,它使用 Ant 风格的路径模式来匹配请求的 URI。 1.1 什么是 Ant 风格的路径模式 Ant 风格的路径模式(Ant Path Matching)是一种用于资源定位的模式匹配规则,它源自 Apache Ant 这个 Java 构建工具。在 Ant 中,这种模式被用来指定文件系统中的文件和目录。由于其简单性和灵活性,Ant 风格的路径模式也被其他许多框架和应用程序所采用,包括 Spring Security。

使用 Key 和 SecretKey 签发 JWT Token

1、概览 JSON Web Tokens(JWT)是用于保护无状态应用的事实上的标准。Spring Security 框架提供了集成 JWT 以保护 REST API 的方法。 本文将带你了解如何在 Spring Boot 应用中创建 SecretKey 实例来签发和验证 JWT。 2、项目设置 2.1、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter-web、spring-boot-starter-security、spring-boot-starter-data-jpa 和 h2 数据库依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>3.2.3</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.2.224</version> </dependency> Spring Boot Starter Web 提供了用于构建 REST API 的 API。Spring Boot Starter Security 用于提供身份认证和授权。h2 是一个内存数据库,方便快速开发。 然后,还要在 pom.xml 中添加 jjwt-api、jjwt-impl 和 jjwt-jackson 依赖: <dependency> <groupId>io.

从 Spring Security 5 迁移到 Spring Security 6/Spring Boot 3

1、概览 Spring Security 6 有几处重大变化,包括删除了一些类和已废弃的方法,并引入了一些新方法。 从 Spring Security 5 迁移到 Spring Security 6 可以在不破坏现有代码的情况下逐步完成。此外,还可以使用 OpenRewrite 等第三方插件来促进向最新版本的迁移。 本文将带你了解如何把 Spring Security 5 的现有应用迁移到 Spring Security 6(替换过时的方法,并利用 Lambda DSL 简化配置。此外,还利用 OpenRewrite 加快迁移速度)。 2、Spring Security 和 Spring Boot 版本 Spring Boot 基于 Spring 框架,各版本的 Spring Boot 使用最新版本的 Spring 框架。Spring Boot 2 默认使用 Spring Security 5,而 Spring Boot 3 使用 Spring Security 6。 要在 Spring Boot 应用中使用 Spring Security,首先需要在 pom.xml 中添加 spring-boot-starter-security 依赖。 可以在 pom.xml 的 properties 部分 指定所需的版本,从而覆盖默认的 Spring Security 版本 :

Spring Security 配置 Basic Authentication

1、概览 本文将带你了解如何通过 Spring Security 提供的 Basic Authentication 机制来保护 MVC 应用。 2、Spring Security 配置 使用 Java 配置来配置 Spring Security: @Configuration @EnableWebSecurity public class CustomWebSecurityConfigurerAdapter { @Autowired private RestAuthenticationEntryPoint authenticationEntryPoint; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user1") .password(passwordEncoder().encode("user1Pass")) .authorities("ROLE_USER"); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(expressionInterceptUrlRegistry -> expressionInterceptUrlRegistry.requestMatchers("/securityNone").permitAll() .anyRequest().authenticated()) .httpBasic(httpSecurityHttpBasicConfigurer -> httpSecurityHttpBasicConfigurer.authenticationEntryPoint(authenticationEntryPoint)); http.addFilterAfter(new CustomFilter(), BasicAuthenticationFilter.class); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 如上,在 SecurityFilterChain Bean 中使用 httpBasic() 来定义 Basic Authentication。