Spring Security OAuth 2 教程 - 2:授权码模式

在 “Spring Security OAuth 2 教程 - 1:熟悉 OAuth 2 概念” 中,我们学习了如何设置 Keycloak、创建 Realm、启用 Standard flow 的客户端和用户。在本文中,我们将了解如何通过 “授权码模式”(Authorization Code Flow)对用户进行身份认证。 首先,让我们澄清一下 “授权码授权方式”(Authorization Code Grant Type)与 “授权码模式”(Authorization Code Flow)之间的混淆。 正如我之前提到的,OAuth 2.0 规范仅关注授权(Authorization),而 OpenID Connect 规范是在 OAuth 2.0 之上添加的一层,用于处理身份认证(Authentication)。 “授权码授权方式”(Authorization Code Grant Type)是 OAuth 2.0 的术语,而 “授权码模式”(Authorization Code Flow)是 OpenID Connect 的术语。它们的工作方式相同,区别在于 scope。通过本文后面的示例,我们将更清楚地了解 “授权码模式” 的差异。 快速回顾一下,我们在上一教程中,创建的客户端(Client)和用户(User)的详细信息如下。 Client id:messages-webapp Client secret:qVcg0foCUNyYbgF0Sg52zeIhLYyOwXpQ Username:siva Password:siva1234 OAuth 2.0 架构 以下是基于 OAuth 2.0 的系统的架构图: 资源所有者(Resource Owner),也就是终端用户,希望使用客户端(Client)应用访问其存储在资源服务器(Resource Server)上的数据。 资源服务器(Resource Server)数据受保护,需要访问令牌(access_token)才能访问数据。 客户端(Client)应用将管理用户、签发访问令牌(access_token)和认证用户的责任转交给了授权服务器(Authorization Server)。 当你(Resource Owner)试图在客户端(Client)应用上访问受保护的资源时,你将被重定向到授权服务器(Authorization Server),在那里你需要通过提供用户凭证来认证自己的身份。 如果认证成功,授权服务器(Authorization Server)就会向客户端(Client)签发访问令牌(access_token)。 然后,客户端(Client)就可以使用访问令牌(access_token)访问受保护的用户的数据了。 这是终端用户如何使用基于 OAuth 2.

Spring Security OAuth 2 教程 - 1:熟悉 OAuth 2 概念

安全是一个需要深入理解的复杂主题。此外,使用 OAuth 2.0 和 OpenID Connect 规范为基于微服务的复杂系统实现认证和授权更加困难。像 Spring Security 这样的框架和库有助于降低复杂性,但要正确实现 Security 仍然需要经历陡峭的学习曲线。 在本 Spring Security OAuth2 系列教程中,我将与大家分享如何使用 Spring Security OAuth2 为基于微服务的应用实现认证和授权。 有许多身份提供商(Identity Provider)解决方案,如 Keycloak、Okta、Auth0 等。在本系列中,我们将使用开源身份和访问管理解决方案 Keycloak。 我不是安全、OAuth2 和 Keycloak 方面的专家。我只是根据自己对这些概念的理解与大家分享我的学习心得。如果你认为其中有任何概念或解释不正确,请指正。 我们不会直接进入 Spring Security OAuth2 的实现,而是先从概念开始学习,循序渐进。 了解 OAuth 2.0 和 OpenID Connect 的基础知识 学习 OAuth 2.0 和 OpenID Connect 的第一步是了解一些核心概念,如 OAuth2 中的各种角色(Role)是什么、各种授权方式(Grant Type)是什么以及何时使用哪种方式。 简而言之,在 OAuth2 系统中,有各种不同的组件扮演着不同的角色,也有不同的方法来验证用户身份。 OAuth2.0 角色(Role) 资源所有者(Resource Owner): 资源所有者通常是终端终用户,他授权应用(客户端)访问他/她的账户。 资源服务器(Resource Server): 托管受保护资源的服务器。这是你要访问的 API。 客户端(Client): 代表资源所有者请求访问受保护资源的应用(资源所有者正在使用的应用)。 授权服务器(Authorization Server): 对资源所有者进行身份验证并在成功授权后发放访问令牌(Access Token)的服务器。 OAuth2.

Spring Cloud 2023 新特性:支持同步网关

网关不支持传统 Servlet 容器 Spring Cloud Gateway 需要运行在提供的 Netty 运行时。它不能在传统的 Servlet 容器中工作,也不能在构建为 WAR 时工作。WebFlux 使用了异步非阻塞的编程模型,相较于传统的 MVC Servlet 需要理解和适应新的编程范式和响应式编程概念,因此学习曲线可能较陡峭。 如果在 spring-cloud-gateway 引入了 tomcat 等传统容器会抛出如下异常: 14 Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat 15 at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:124) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 16 at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:86) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 17 at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:414) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 18 at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:178) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 19 at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:179) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 20 at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:152) ~[spring-boot-2.1.6.RELEASE.jar:2.1.6.RELEASE] 21 ... 8 common frames omitted MVC Servlet 支持 在 SpringCloud 2023 版本(Spring Cloud Gateway 4.

在 Liberica 运行时容器上运行 Spring Boot 应用

1、简介 在本教程中,我们将了解如何把使用 Spring Boot 创建的 Java 应用作为 Docker 容器运行,具体来说,我们将在 Alpaquita Linux 上使用 Liberica JDK 来创建运行我们应用的 Docker 镜像。 Liberica JDK 和 Alpaquita Linux 是 BellSoft 产品的一部分。BellSoft 的愿景是使 Java 成为云原生应用程序的首选语言。 2、简单的 Spring Boot 应用 先用 Java 创建一个简单的应用,然后将其容器化。通过 Spring Boot,我们只需进行最少的配置,就能轻松创建基于 Spring 的独立生产级应用。 初始化 Spring Boot 应用的最简单方法是使用 Spring Boot CLI。通过它,可以在命令行中使用 start.springboot.io 创建一个新项目: $ spring init --build=gradle --dependencies=web spring-bellsoft 如上,添加了 web 依赖,以构建 RESTful API,并将 Apache Tomcat 作为默认的嵌入式容器。选择 Gradle 作为构建工具,默认的语言是 Java。 然后,可以将生成的项目导入 IDE(如 IntelliJ Idea),开始开发应用。 添加一个简单的 REST API,接收一个 Integer 参数,并返回等于或小于该数字的斐波纳契数列:

Spring Security:升级已弃用的 WebSecurityConfigurerAdapter

1、概览 Spring Security 允许通过继承 WebSecurityConfigurerAdapter 类来自定义 HTTP Security,例如端点授权或 Authentication Manager 配置。然而,在最近的版本中,Spring 已经弃用了这种方法,并推荐使用基于组件的 security 配置。 本文将会带你学习如何在 Spring Boot 应用中代替这些已废弃的方法。 2、Spring Security 不使用 WebSecurityConfigurerAdapter 常见的 Spring HTTP Security 配置类都会继承一个 WebSecurityConfigureAdapter 类。 从 5.7.0-M2 起,WebSecurityConfigureAdapter 被废弃了,不推荐使用。 创建一个基于内存验证的 Spring Boot 应用示例来演示如何进行新的配置。 首先,定义配置类: @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) public class SecurityConfig { // config } 添加 Method Security 注解,根据不同角色进行处理。 2.1、配置 Authentication 使用 WebSecurityConfigureAdapter 时,使用 AuthenticationManagerBuilder 来设置 Authentication Context。 现在,可以定义一个 UserDetailsManager 或 UserDetailsService 来避免组件过时的问题:

在 Spring Boot Properties/Yaml 文件中使用环境变量

1、概览 本文介绍了如何在 Spring Boot 的 application.properties 和 application.yml 中使用环境变量,以及如何在代码中使用这些属性。 2、在 application.properties 文件中使用环境变量 定义一个名为 JAVA_HOME 的全局环境变量,其值为 C:\Program Files\Java\jdk-11.0.14。 要在 Spring Boot 的 application.properties 中使用该变量,需要用大括号将其包裹起来: java.home=${JAVA_HOME} 也可以以同样的方式使用系统属性(System Properties)。例如,在 Windows 系统中,默认情况下会定义操作系统属性: environment.name=${OS} 还可以组合多个变量值。定义另一个环境变量 HELLO_BAELDUNG,其值为 Hello Baeldung。现在可以将两个变量连接起来: baeldung.presentation=${HELLO_BAELDUNG}. Java is installed in the folder: ${JAVA_HOME} baeldung.presentation 属性值现在为:Hello Baeldung. Java is installed in the folder: C:\Program Files\Java\jdk-11.0.14. 3、在代码中使用特定环境属性 启动 Spring Context 后,就可以在代码中注入属性值。 3.1、使用 @Value 注入属性值 可以使用 @Value 注解在 setter 方法、构造器和字段上进行注入: @Value("${baeldung.presentation}") private String baeldungPresentation; 3.2、从 Spring Environment 获取值 还可以通过 Spring 的 Environment 获取属性值。

Spring Boot 3 和 Spring Framework 6.0 - 新功能

1、概览 本文简单地介绍了 Spring Boot 3 和 Spring Framework 6.0 中的新特性。 2、Java 17 之前已经支持Java 17,现在这个 LTS 版本成为基线版本。 由于 Java 本身不是本文的主题,这里只会列举对 Spring Boot 开发人员最重要的新特性。 2.1、Record Java Record(JEP 395),是一种快速创建数据类(Data Class)方式,即那些目的仅仅是包含数据并在模块之间传递数据的类,也被称为 POJO(Plain Old Java Objects,简单Java对象)和 DTO(Data Transfer Objects,数据传输对象)。 使用 Record 可以轻松创建不可变的 DTO: public record Person (String name, String address) {} 目前,在将它们与 Bean Validation 结合使用时,需要小心,因为构造函数参数不支持验证约束,例如在 Controller 方法中的 JSON 对象。 2.2、字符块 通过 JEP 378,现在就可以创建多行文本块,而无需在换行时连接字符串: String textBlock = """ Hello, this is a multi-line text block. """; 2.

Spring Boot 整合 Redisson

Redisson 是一个功能十分强大的 Redis Java 客户端,它提供了丰富的功能和API,支持同步和异步操作,以及 RxJava 和响应式编程模型。Redisson 提供了50多个基于 Redis 的 Java 对象和服务,包括 分布式锁、原子计数器、分布式集合(Set、Map、List、Queue) 等高级功能。它还还支持本地缓存和 RPC 调用等功能,是开发分布式应用和使用 Redis 的理想选择。 总之,Redisson 所提供的功能已经远远超出了一个 Redis 客户端的范畴,Redis 官方也 推荐使用它 作为 Java 的 Redis 客户端。 之前我们介绍过 如何在 Spring Boot 中整合、使用 Redis。我们用到了 Spring Data Redis 组件,这是由 Spring 提供的抽象,可以使用 Jedis、Lettuce 等客户端作为实现。 Redisson 官方提供了一个 redisson-spring-boot-starter 组件,它正是 Spring Data Redis 抽象的实现,也就是说,我们可以直接使用 redisson-spring-boot-starter 无缝替换 spring-boot-starter-data-redis。 本文将会带你了解如何在 Spring Boot 中通过 redisson-spring-boot-starter 整合、使用 Redisson。 整合 Redisson 添加依赖 添加 redisson-spring-boot-starter 依赖即可。 <!-- https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter --> <dependency> <groupId>org.

Spring OpenFeign 的异常处理

1、概览 微服务间的 HTTP API 调用可能会出现异常。在 Spring Boot 中使用 OpenFeign 时,默认会把下游服务的 “Not Found” 等异常全部当做 “Internal Server Error” 响应给客户端。这并不是异常的最佳处理方式,幸而,Spring 和 OpenFeign 都提供了一些机制,允许我们自定义异常处理。 本文将带你了解,Spring Boot 和 OpenFeign 默认的异常传播、处理机制,以及如何实现自定义的异常处理。 2、默认的异常传播策略 2.1、Feign 中默认的异常传播 Feign 使用 ErrorDecoder.Default 内部实现类进行异常处理。每当 Feign 收到任何非 2xx 状态码时,都会将其传递给 ErrorDecoder 的 decode 方法。 如果 HTTP 响应有 Retry-After 头信息,decode 方法就会返回 RetryableException,否则就会返回 FeignException。 重试时,如果请求在默认重试次数之后仍然失败,则会返回 FeignException。 decode 方法将 HTTP 方法 key 和响应存储在 FeignException 中。 2.2、Spring Rest Controller 中的默认异常传播 只要 RestController 收到任何未处理的异常,它就会向客户端返回 500 Internal Server Error(内部服务器错误)响应。 该异常响应包含时间戳、HTTP 状态码、异常信息和路径等信息:

构建自己的 Spring Initializr 服务

Spring Initializr 是 Spring 官方提供的一个用于快速创建和初始化 Spring 项目的在线工具。它可以让开发人员选择所需的 Spring 模块、版本、语言(Java、Kotlin 或 Groovy)和构建工具(Maven 或 Gradle),并生成一个基本的项目结构。现在大多数 IDE 都对 Spring Initializr 提供了支持! 官方的 Spring Initializr 服务(start.spring.io)部署在海外,在国内访问经常出现各种连网络接失败的问题。好在 Spring Initializr 是一个开源的项目,我们可以用它来构建自己的 Spring Initializr 服务。 Spring Initializr Github 仓库:https://github.com/spring-io/start.spring.io 构建 Spring Initializr 服务 Clone 项目 需要先在机器上安装 git 软件。 git clone https://github.com/spring-io/start.spring.io.git 该仓库下有三个工程,我们只关心其中2个: start-client 前端工程,使用 React 开发。 start-site 后端工程,是一个 Spring Boot 应用。 执行构建 项目使用 maven 构建,且提供了 mvnw(Maven Wrapper) 脚本,它是一个用于管理和运行 Maven 项目的工具。它的作用是在没有全局安装 Maven 的情况下,通过自动下载和配置特定版本的 Maven 来确保项目的构建和运行环境一致性。也就是说 不需要在本地安装 Maven,通过此脚本即可完成构建。 进入项目根目录,执行如下命令进行自动构建: