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。

Spring Security 设置 Authentication Provider

1、概览 本文将带你了解如何在 Spring Security 中设置 Authentication Provider,相比于使用简单的 UserDetailsService 的标准方案,这样可以提供额外的灵活性。 2、Authentication Provider Spring Security 提供了多种执行身份认证的选项。这些选项遵循一个简单的契约;一个 AuthenticationProvider 处理一个身份认证请求,并返回一个带有完整凭证的认证对象。 最常见的标准实现是 DaoAuthenticationProvider,它从一个简单的 UserDetailsService(只读)中获取用户详细信息。这个 Service 只能通过用户名检索完整的用户实体,这在大多数情况下已足够。 更多的自定义场景仍需要访问完整的认证请求才能执行身份验证流程。例如,在对某些外部第三方服务进行身份验证时,身份认证请求中的 username 和 password 都是必要的。 对于这些更高级的场景,需要定义一个自定义的 Authentication Provider: @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String name = authentication.getName(); String password = authentication.getCredentials().toString(); if (shouldAuthenticateAgainstThirdPartySystem()) { // 使用凭证并对第三方系统进行身份认证 return new UsernamePasswordAuthenticationToken( name, password, new ArrayList<>()); } else { return null; } } @Override public boolean supports(Class<?

Spring Security 控制 Session

1、概览 本文将带你了解如何在 Spring Security 中配置 Session 超时、Session 并发以及其他高级的 Session 安全设置。 2、何时创建 Session? 可以精确控制 Session 的创建时间,以及 Spring Security 与 Session 的交互方式: always:如果 Session 不存在,则会创建一个 Session。 ifRequired:仅在需要时才创建 Session(默认值)。 never:框架不会自己创建 Session,但如果 Session 已经存在,则会使用该 Session。 stateless:Spring Security 不会创建或使用 Session。 <http create-session="ifRequired">...</http> Java 配置如下: @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) return http.build(); } 注意,该配置只控制 Spring Security 的行为,而不是整个应用。如果指定 Spring Security 不创建 Session,它就不会创建 Session,但是应用可能会创建 Session! 默认情况下,Spring Security 会在需要时创建一个 Session,即 ifRequired。 对于无状态应用,never 选项将确保 Spring Security 本身不会创建任何 Session。但如果应用创建了 Session,Spring Security 就会使用它。

在 Spring Security 中获取当前用户

1、概览 本文介绍了如何在 Spring Security 中检索当前用户详细信息。 2、从 Bean 中获取用户 检索当前已通过身份认证用户(Principal)的最简单方式是调用 SecurityContextHolder 的静态方法: Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String currentPrincipalName = authentication.getName(); 该代码需要改进的地方在于,在尝试访问之前,首先要检查是否存在已通过身份认证的用户: Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (!(authentication instanceof AnonymousAuthenticationToken)) { String currentUserName = authentication.getName(); return currentUserName; } 当然,这样的静态调用也有缺点,代码的可测试性降低了。 3、在 Controller 中获取用户 在 @Controller 中,可以直接将 Principal 定义为方法参数,这样框架就能正确地解析: @Controller public class GetUserWithPrincipalController { @RequestMapping(value = "/username", method = RequestMethod.GET) @ResponseBody public String currentUserName(Principal principal) { return principal.getName(); } } 或者,也可以使用 Authentication Token: @Controller public class GetUserWithAuthenticationController { @RequestMapping(value = "/username", method = RequestMethod.