[译]Spring Boot3和Spring6中的新特性

Spring Boot 3.0 于 2022 年 11 月正式发布,包含一些新功能和改进。这是继大约 4.5 年前发布 Spring Boot 2.0 后 Spring Boot 的第一个主要版本。它也是第一个支持 Spring Framework 6.0 的 Spring Boot GA 版本。作为开发人员,我们需要了解这些更新,才能顺利使用 Spring Boot。毫无疑问,新版本中最大的转变之一是放弃了对旧版本 Java 的支持。 在本文中,我们将讨论“Spring Boot 3 和 Spring 6 中的新功能”。 Spring 3.0 版本有哪些主要亮点? Spring 3.0 版本的亮点包括: Java 17 基线 支持 Jakarta EE 10 和 EE 9 基线 支持使用 GraalVM 生成本机映像,取代实验性 Spring Native 项目 通过测微计和测微计追踪提高了可观测性 谁可以真正使用 Spring Boot 3? 如前所述,Spring Boot 3.0 最大的转变是忽略了对旧版本 Java 的支持。是的,我们至少需要 Java 17 才能使用 Spring Boot 3.0。因此,在使用 Spring Boot 3.0 之前必须具备 JDK 17 环境。 Spring Boot 3 和 Spring 6 有哪些新功能? 这里需要注意的重要一点是 Spring Boot 3.0 构建于 Spring Framework 6 之上并需要 Spring Framework 6。因此,如果您的 pom....

[译]SPRING BOOT JWT - 如何使用 SPRING SECURITY 和 JSON WEB 令牌保护您的 REST API

如果您快速搜索如何使用 JSON Web Tokens 在 Spring Boot 中保护 REST API,您会发现很多相同的结果。这些结果包含一种方法,该方法涉及编写自定义过滤器链并引入第三方库来编码和解码 JWT。 在看完这些令人费解且令人困惑的教程后,我说必须有一种更简单的方法来做到这一点。我做了任何直接接触 Spring Security 团队的人都会做的事情,我向他们寻求帮助。他们告诉我,Spring Security 确实使用 oAuth2 资源服务器内置了对 JWT 的支持。 在本教程中,您将学习如何使用 JSON Web Tokens (JWT) 和 Spring Security 来保护您的 API。我并不是说这种方法无论如何都很容易,但对我来说,它比其他选择更有意义。 Github 存储库 应用架构 在我们开始编写一些代码之前,我想确保我们对于我们正在构建的内容都达成共识。在下面的示例中,您有一个客户端应用程序,它可以是一个简单的命令行应用程序、一个用 Angular 或 Vue 等编写的完整前端应用程序,或者系统中的其他一些服务。 该客户端应用程序将调用使用 Spring Boot 编写的服务器应用程序,该应用程序通过 REST API 公开数据。在下面的示例中,它是一个整体,但如果您有分布式架构,则同样适用。当前有 3 个 REST 控制器公开资源产品、订单和客户。 您要做的是保护所有资源,以便当客户端调用 REST API 时,客户端将收到 401(未经授权),这意味着客户端请求尚未完成,因为它缺少所请求资源的有效身份验证凭据。 JSON 网络令牌 (JWT) JSON Web 令牌是一种开放方法,用于在两方之间安全地表示声明。 JWT 是一组声明(JSON 属性-值对),它们共同构成一个 JSON 对象。它由三部分组成: Header: 由两个属性组成:{ “alg”: “HS256”, “typ”: “JWT” }。 alg 是用于加密 JWT 的算法。 Payload: 这是存储要发送的数据的地方;该数据存储为 JSON 属性-值对。 Signature: 这是通过加密创建的,使用标头中指定的算法:(i)base64Url 编码的标头,(ii)base64Url 编码的有效负载,以及(iii)秘密(或私钥): HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret|privateKey) 最终的 JWT 由三部分组成。每个都是 base64Url 编码的,并且与下一个之间用点分隔。有关更多详细信息,请参阅 openid.net 和 jwt.io 网站。...

[译]Spring Security 与 JWT for REST API

免责声明:Spring Security 5+ 已发布 OAuth JWT 支持。建议使用最新版本的 OAuth 来支持 JWT,而不是使用自定义安全性或过滤器。 Spring 被认为是 Java 生态系统中值得信赖的框架,并且被广泛使用。将 Spring 称为框架不再有效,因为它更多的是涵盖各种框架的总括术语。其中一个框架是 Spring Security,它是一个功能强大且可定制的身份验证和授权框架。它被认为是保护基于 Spring 的应用程序的事实标准,因此,如果您希望实现 Spring JWT 令牌解决方案,那么将其基于 Spring Security 是有意义的。 尽管它很受欢迎,但我必须承认,当涉及到单页应用程序时,Spring 的配置并不简单和直接。我怀疑原因是它更多地是作为一个面向应用程序的 MVC 框架开始的,其中网页渲染发生在服务器端,并且通信是基于会话的。 如果后端基于 Java 和 Spring,那么使用 Spring Security 和 JWT 进行身份验证/授权并将其配置为无状态通信是有意义的。虽然有很多文章解释了这是如何完成的,但对我来说,第一次设置它仍然令人沮丧,我必须阅读并总结来自多个来源的信息。这就是我决定编写这个 Spring Security 教程的原因,我将在其中尝试总结并涵盖您在配置过程中可能遇到的所有必需的微妙细节和缺陷。 术语定义 在深入探讨技术细节之前,我想明确定义 Spring Security 上下文中使用的术语,以确保我们都使用相同的语言。 这些是我们需要解决的术语: Authentication 验证是指根据提供的凭据验证用户身份的过程。一个常见的示例是在登录网站时输入用户名和密码。您可以将其视为对“您是谁?”这个问题的答案。 Authorization 授权是指假设用户已成功通过身份验证,则确定用户是否具有执行特定操作或读取特定数据的适当权限的过程。您可以将其视为“用户可以执行/阅读此操作吗?”问题的答案。 Principle 原则是指当前经过身份验证的用户。 Granted authority 授予权限是指经过认证的用户的权限。 Role 角色是指经过身份验证的用户的一组权限。 创建基本的 Spring 应用程序 在开始配置 Spring Security 框架之前,让我们创建一个基本的 Spring Web 应用程序。为此,我们可以使用 Spring Initializr 并生成一个模板项目。对于一个简单的 Web 应用程序,只需要 Spring Web 框架依赖就足够了: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> 创建项目后,我们可以向其中添加一个简单的 REST 控制器,如下所示: @RestController @RequestMapping("hello") public class HelloRestController { @GetMapping("user") public String helloUser() { return "Hello User"; } @GetMapping("admin") public String helloAdmin() { return "Hello Admin"; } } 之后,如果我们构建并运行该项目,我们可以在 Web 浏览器中访问以下 URL:...

[译]REST API 的自定义错误消息处理

1. 概述 在本教程中,我们将讨论如何为 Spring REST API 实现全局错误处理程序。 我们将使用每个异常的语义为客户端构建有意义的错误消息,其明确的目标是为客户端提供所有信息以轻松诊断问题。 2. 自定义错误消息 让我们首先实现一个用于通过线路发送错误的简单结构 — ApiError: public class ApiError { private HttpStatus status; private String message; private List<String> errors; public ApiError(HttpStatus status, String message, List<String> errors) { super(); this.status = status; this.message = message; this.errors = errors; } public ApiError(HttpStatus status, String message, String error) { super(); this.status = status; this.message = message; errors = Arrays.asList(error); } } 这里的信息应该很简单: status – HTTP 状态代码 message – 与异常相关的错误消息 error – 构建的错误消息列表 当然,对于 Spring 中的实际异常处理逻辑,我们将使用 @ControllerAdvice 注解: @ControllerAdvice public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler { ... } 3. 处理错误请求异常 3.1.处理异常 现在让我们看看如何处理最常见的客户端错误 - 基本上是客户端向 API 发送无效请求的情况: BindException – 发生致命绑定错误时抛出此异常。 MethodArgumentNotValidException – 当使用 @Valid 注解的参数验证失败时抛出此异常: @Override protected ResponseEntity<Object> handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { List<String> errors = new ArrayList<String>(); for (FieldError error : ex....

[译]使用Spring进行REST的错误处理

1. 概述 本教程将说明如何使用 Spring 为 REST API 实现异常处理。我们还将获得一些历史概述,并了解不同版本引入了哪些新选项。 在 Spring 3.2 之前,Spring MVC 应用程序中处理异常的两种主要方法是 HandlerExceptionResolver 或 @ExceptionHandler 注解。两者都有一些明显的缺点。 从 3.2 开始,我们使用了 @ControllerAdvice 注释来解决前两个解决方案的局限性,并促进整个应用程序的统一异常处理。 现在 Spring 5 引入了 ResponseStatusException 类,一种在 REST API 中进行基本错误处理的快速方法。 所有这些都有一个共同点:它们很好地处理了关注点分离。应用程序可以正常抛出异常来指示某种失败,然后将单独处理。 最后,我们将了解 Spring Boot 带来的功能以及如何配置它以满足我们的需求。 2.方案一:控制器级@ExceptionHandler 第一个解决方案在 @Controller 级别工作。我们将定义一个处理异常的方法并使用@ExceptionHandler 进行注释: public class FooController{ //... @ExceptionHandler({ CustomException1.class, CustomException2.class }) public void handleException() { // } } 这种方法有一个主要缺点:· 注解的方法仅对特定的控制器有效,而不是对整个应用程序全局有效。当然,将其添加到每个控制器使其不太适合通用异常处理机制。 我们可以通过让所有控制器扩展基本控制器类来解决此限制。 然而,对于无论出于何种原因这是不可能的应用程序来说,此解决方案可能是一个问题。例如,控制器可能已经从另一个基类扩展,该基类可能位于另一个 jar 中或不可直接修改,或者本身可能不可直接修改。 接下来,我们将研究另一种解决异常处理问题的方法 - 一种全局的方法,不包括对现有工件(例如控制器)的任何更改。 3.解决方案 2:HandlerExceptionResolver 第二种解决方案是定义一个 HandlerExceptionResolver。这将解决应用程序抛出的任何异常。它还允许我们在 REST API 中实现统一的异常处理机制。 在选择自定义解析器之前,让我们先回顾一下现有的实现。 3.1.异常处理器异常解析器 该解析器是在 Spring 3.1 中引入的,并且在 DispatcherServlet 中默认启用。这实际上是前面介绍的 @ExceptionHandler 机制如何工作的核心组件。 3.2.默认处理程序异常解析器 这个解析器是在 Spring 3.0 中引入的,并且在 DispatcherServlet 中默认启用。 它用于将标准 Spring 异常解析为其相应的 HTTP 状态代码,即客户端错误 4xx 和服务器错误 5xx 状态代码。以下是它处理的 Spring 异常的完整列表以及它们如何映射到状态代码。...

[译]使用@Async进行Spring Security上下文传播

1. 简介 在本教程中,我们将重点关注使用 @Async 传播 Spring Security 主体 默认情况下,Spring Security 身份验证绑定到 ThreadLocal - 因此,当执行流在带有 @Async 的新线程中运行时,它不会是经过身份验证的上下文。 这并不理想——让我们解决它。 2.Maven 依赖 为了在 Spring Security 中使用异步集成,我们需要在 pom.xml 的依赖项中包含以下部分: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.7.3</version> </dependency> 可以在此处找到最新版本的 Spring Security 依赖项。 3.使用@Async 进行 Spring Security 传播 我们先写一个简单的例子: @RequestMapping(method = RequestMethod.GET, value = "/async") @ResponseBody public Object standardProcessing() throws Exception { log.info("Outside the @Async logic - before the async call: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); asyncService.asyncCall(); log.info("Inside the @Async logic - after the async call: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return SecurityContextHolder.getContext().getAuthentication().getPrincipal(); } 我们想要检查 Spring SecurityContext 是否传播到新线程。首先,我们在异步调用之前记录上下文,接下来我们运行异步方法,最后再次记录上下文。 asyncCall() 方法具有以下实现: @Async @Override public void asyncCall() { log.info("Inside the @Async logic: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); } 正如我们所看到的,只有一行代码将输出异步方法的新线程内的上下文。...

[译]Spring Events

1. 概述 在本教程中,我们将讨论如何在 Spring 中使用事件。 事件是框架中最容易被忽视的功能之一,但也是最有用的功能之一。与 Spring 中的许多其他功能一样,事件发布是 ApplicationContext 提供的功能之一。 有一些简单的准则需要遵循: 如果我们使用 Spring Framework 4.2 之前的版本,事件类应该扩展 ApplicationEvent。从 4.2 版本开始,事件类不再需要扩展 ApplicationEvent 类。 发布者应该注入一个 ApplicationEventPublisher 对象。 监听器应该实现 ApplicationListener 接口。 2. 自定义事件 Spring 允许我们创建和发布默认情况下同步的自定义事件。这有一些优点,例如侦听器能够参与发布者的事务上下文。 2.1.一个简单的应用程序事件 让我们创建一个简单的事件类——只是一个存储事件数据的占位符。 在本例中,事件类保存一条字符串消息: public class CustomSpringEvent extends ApplicationEvent { private String message; public CustomSpringEvent(Object source, String message) { super(source); this.message = message; } public String getMessage() { return message; } } 2.2.发布者 现在让我们创建该事件的发布者。发布者构造事件对象并将其发布给正在侦听的任何人。 要发布事件,发布者只需注入 ApplicationEventPublisher 并使用 publishEvent() API: @Component public class CustomSpringEventPublisher { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void publishCustomEvent(final String message) { System.out.println("Publishing custom event. "); CustomSpringEvent customSpringEvent = new CustomSpringEvent(this, message); applicationEventPublisher.publishEvent(customSpringEvent); } } 或者,发布者类可以实现 ApplicationEventPublisherAware 接口,这也将在应用程序启动时注入事件发布者。通常,使用 @Autowire 注入发布者会更简单。...

[译]如何在Spring中执行@Async

1. 概述 在本教程中,我们将探讨 Spring 中的异步执行支持和 @Async 注解。 简单地说,用 @Async 注解 bean 的方法将使其在单独的线程中执行。换句话说,调用者不会等待被调用方法的完成。 Spring 的一个有趣的方面是,框架中的事件支持还 支持异步处理(如果需要)。 2.启用异步支持 让我们首先通过 Java 注解启用异步处理。 我们将通过将 @EnableAsync 添加到配置类来完成此操作: @Configuration @EnableAsync public class SpringAsyncConfig { ... } 启用注解就足够了。但也有一些简单的配置选项: annotation 默认情况下,@EnableAsync 检测 Spring 的 @Async 注解和 EJB 3.1 javax.ejb.Asynchronous。我们也可以使用此选项来检测其他用户定义的注解类型。 mode 指示应使用的建议类型 - 基于 JDK 代理或 AspectJ 编织。 proxyTargetClass 指示应使用的代理类型 — CGLIB 或 JDK。仅当模式设置为 AdviceMode.PROXY 时,此属性才有效。 order 设置应用 AsyncAnnotationBeanPostProcessor 的顺序。默认情况下,它最后运行,以便它可以考虑所有现有代理。 我们还可以使用任务命名空间通过 XML 配置启用异步处理: <task:executor id="myexecutor" pool-size="5" /> <task:annotation-driven executor="myexecutor"/> 3.@Async 注解 首先,让我们回顾一下规则。 @Async 有两个限制: 它必须仅应用于公共方法。 自调用(从同一个类中调用异步方法)将不起作用。 原因很简单:该方法需要公开,以便可以被代理。并且自调用不起作用,因为它绕过代理并直接调用底层方法。 3.1.返回类型为 void 的方法 这是配置具有 void 返回类型的方法以异步运行的简单方法: @Async public void asyncMethodWithVoidReturnType() { System.out.println("Execute method asynchronously. " + Thread.currentThread().getName()); } 3.2.具有返回类型的方法 我们还可以通过将实际返回包装在 Future 中来将 @Async 应用于具有返回类型的方法:...

[译]Spring Boot项目如何实现JWT认证?

没有人可以否认这样一个事实:安全性是生产就绪应用程序的一项重要功能。尽管我们可以使用内存身份验证、JDBC 身份验证或通过 UserDetailsS​​ervice 来保护一个 Web 应用程序的安全。但是,当一个应用程序在内部使用其他应用程序的服务时,使用 Web 服务概念实现安全性就变得很重要。在这种情况下,我们使用具有特定有效期的令牌来保护我们的应用程序。此外,我们将学习“如何在 Spring Boot 项目中实现 JWT 身份验证?”以整体了解 JWT(JSON Web Token)身份验证背后的概念。 由于 JWT 代表“JSON Web Token”,很明显,该令牌仅以 JSON 形式保存数据。 此外,与上述身份验证技术不同,JWT 属于无状态身份验证。简而言之,它没有数据。通常,这种类型的身份验证用于 Web 服务、服务器的水平扩展,甚至在某种程度上用于 OAuth 技术。为了说明该网络服务,让我们可视化从亚马逊预订订单的过程。在这里,用户与 Amazon 应用程序交互,而 Amazon 应用程序在内部通过 Web 服务调用与支付网关应用程序交互。 现在让我们开始讨论我们的主题“如何在 Spring Boot 项目中实现 JWT 身份验证?”以及相关点。 您对整篇文章有何期望? 读完本文后,您将能够回答: 什么是安全上下文中的无状态和有状态身份验证? 无状态认证和有状态认证有什么区别? 那么什么是 Token,什么是 JWT(JSON Web Token)? 使用 JWT 认证有什么好处? JWT 内部如何运作? 我们在什么情况下使用 JWT 身份验证? 此外,JWT 身份验证和状态身份验证之间有什么区别? 此外,如何生成 JWT 编码令牌以及如何将其解码回来? 如何在 Spring Boot 项目中逐步实现 JWT 认证? 在 Spring Boot 3.0 中,如何在不使用 WebSecurityConfigurerAdapter 的情况下编写安全配置类? 最后,如何测试启用 JWT 安全的应用程序? 什么是无状态和有状态身份验证? 通常有两种类型的认证技术。两者都发生在客户端服务器概念中,服务器仅在身份验证后才向客户端提供服务。这里的客户端可以是浏览器,也可以是另一个服务器。 状态认证 在这种类型的身份验证中,客户端和服务器之间涉及会话管理。当客户端向服务器请求服务时,它首先登录到服务器。然后服务器创建一个会话并以键值对的形式存储该信息。这个会话是服务器端的一种内存。我们也称其为 HttpSession,因为 Http 协议管理它。 此外,为了响应客户端请求,服务器以 Cookie 的形式向客户端提供带有响应的会话 id。该 cookie 存储在客户端浏览器中。当同一个客户端第二次发出请求时,请求头中也会带有 cookie。因此,服务器会检查请求标头,如果在 cookie 中发现相同的 SID(会话 ID),则假定该请求来自同一客户端。通过这种方式,会话管理就发生了。 当客户端从服务器注销时,会话会相应地被销毁。结果,服务器相应地从内存中删除会话信息(键值)。同样重要的是,对于每个新客户端,服务器都会创建一个新会话(内存)。 无状态身份验证 当客户端向服务器发送服务请求时,它首先登录到服务器。因此,服务器生成一个令牌(编码格式的数据)并将响应发送到客户端。在发出第二个请求时,客户端将相同的令牌与请求一起发送到服务器。现在,服务器从请求中读取令牌并验证令牌。事实上,从第一个请求开始,服务器就检查客户端的有效登录(凭据)。...

[译]没有WebSecurityConfigurerAdapter的Spring Security.md

在 Spring Security 模块的上下文中,WebSecurityConfigurerAdapter 是一个抽象类,根据 Spring 官方网站 2022 年 2 月 21 日发布的公告,该类已从 Spring Security 5.7.0-M2 中弃用。它通常用于扩展 configure() 方法由自定义配置子类实现。因此,它鼓励用户转向基于组件的安全配置。为了支持对这种新配置设计的更改,我们将讨论常见用例列表和未来建议的替代方案。因此,我们将讨论没有 WebSecurityConfigurerAdapter 的 Spring Security 用例的实现。 了解这一变化很重要,因为迟早我们将使用最新版本的 Spring Security 来开发安全功能。让我们讨论“没有 WebSecurityConfigurerAdapter 的 Spring Security”主题及其相关概念。 什么是 WebSecurityConfigurerAdapter? WebSecurityConfigurerAdapter 是 Spring Security 模块提供的一个抽象类。一般来说,我们使用它来重写它的 configure()方法来定义我们的安全配置类。通常,我们在应用程序中实现 Spring Security 时使用两个具有不同参数的 configure() 方法。一种用于声明与身份验证相关的配置,另一种用于声明与授权相关的配置。该代码类似于下面的代码片段。 @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // configure Authentication ...... } @Override protected void configure(HttpSecurity http) throws Exception { // configure Authorization ...... } } 为什么我们需要学习这个改变? 如果您使用 Spring Boot 2.7.0 和 maven,它将自动下载 Spring Security 5.7.0 或更高版本。在这种情况下,您会发现 WebSecurityConfigurerAdapter 已被弃用。如果您仍然想使用此类而不弃用,您可以在 pom.xml 中将 Spring Boot 版本更改为较低版本(例如 2.6.6 ),如下所示。它将自动下载低于 5....