在生产环境中关闭 Swagger-UI

1、概览 在开发环境下使用 Swagger UI 可以很方便地查看、测试 REST 服务。但是出于安全考虑,在生产环境中往往需要禁用 Swagger UI。 2、Swagger 配置 要 使用 SpringDoc 设置 Swagger,需要在配置 Bean 中对其进行定义。 创建 SwaggerConfig 类: @Configuration public class SwaggerConfig { @Bean public OpenAPI openAPI() { return new OpenAPI().info(new Info().title("SpringDoc Disable SwaggerUI example") .description("SpringDoc Disable SwaggerUI application") .version("v0.0.1")); } } 默认情况下,该配置 Bean 会添加到 Spring Context 中。这样,Swagger 可以在所有环境中使用。 3、使用 Spring Profile 在 Spring 中,可以使用 @Profile 注解来启用或禁用 Bean。 使用 SpEL 表达式来指定在哪些环境中激活 Swagger。 @Profile({"!prod && swagger"}) 如上,在 swagger Profile,且不是 prod Profile 的情况下才会启注解的 Bean。

自定义 Keycloak 的登录页面

1、概览 Keycloak 是第三方授权服务器,用于管理 Web 或移动应用的身份验证和授权。它为用户提供了一个默认的登录页面。 本文将带你了解如何自定义 Keycloak 服务器的登录页面。 本文在 《自定义 Keycloak 主题》 基础上进行实现。 2、独立 Keycloak 服务器 继续以 custom 主题为例,先看看独立服务器。 2.1、管理控制台设置 进入 Keycloak 目录,然后在 bin 文件夹中运行如下命令,启动服务器: kc.[sh|bat] start-dev --spi-theme-static-max-age=-1 --spi-theme-cache-themes=false --spi-theme-cache-templates=false 使用上述命令启动服务器后,只需刷新页面,就能看到更改。 现在,在 themes/custom 目录中新建一个名为 login 的文件夹。为了简单起见,先将 themes/keycloak/login 目录中的所有内容复制到这里。这是默认的登录页面主题。 然后,进入管理控制台(http://localhost:8080/admin/master/console),使用 initial1/zaq1!QAZ 凭证登录,并进入 Realm 的 “Themes” 选项卡: 为 Login Theme 选择 custom,然后保存更改。 现在就可以尝试一些自定义功能了。不过在此之前,先来看看默认登录页面: 2.2、添加自定义内容 现在,假设我们需要更改背景。 打开 login/resources/css/login.css 并更改 class 定义: .login-pf body { background: #39a5dc; background-size: cover; height: 100%; } 刷新页面即可看到效果: 接下来,尝试更改用户名和密码的标签。

自定义 Keycloak 主题

1、概览 Keycloak 是一个开源的身份和访问管理(Identity and Access Management,IAM)解决方案,可以作为第三方授权服务器来管理 Web 或移动应用的身份验证和授权。 本文将带你了解如何自定义 Keycloak 的主题,为终端用户的网页提供不同的外观。 本文以之前的文章为基础:《Keycloak 指南》和《在 Spring Boot 中嵌入 Keycloak》。因此,对于初学者来说,最好先阅读这两篇文章。 2、Keycloak 的主题 2.1、默认主题 Keycloak 中预置了几个主题,并与发行版绑定在一起。 对于单机版服务器,可在 ../lib/lib/main/org.keycloak.keycloak-themes-20.0.3.jar(可使用任何标准 ZIP 压缩工具打开)的主题目录下的不同文件夹中找到这些主题: base:包含 HTML 模板和 Message Bundle 的骨架主题;所有主题(包括自定义主题)一般都继承自 base 主题 keycloak:包含用于美化页面的图片和样式表;如果我们不提供自定义主题,则默认使用该主题 keycloak.v2:基于 React 的主题;新管理控制台的一部分;旧控制台已过时,将在 Keycloak 21 中移除。 不建议修改现有主题。相反,应该创建一个新主题,从上述两个主题中继承。 要创建一个新的自定义主题,需要在 themes 目录中添加一个新的文件夹,称之为 custom。如果想要完全重建,则建议从 base 文件夹中复制内容。 在本例中,我们并不打算替换所有内容,因此从 keycloak 目录中获取内容。 2.2、主题类型 Keycloak 支持五种主题: Welcome:用于欢迎页 Login:用于登录、OTP、授予、注册和忘记密码页面 Account:用于用户账户管理页面 Admin Console:用于管理控制台 Email:用于服务器发送的电子邮件 上述列表中的最后四个主题可以通过独立服务器的管理控制台进行设置。当我们在 themes 目录下创建一个新文件夹后,服务器重启后就可以选择该文件夹。 使用凭证 initial1 / zaq1!QAZ(在 上一文章 中设置的)登录管理控制台,并转到 Realm 的 “Themes” 选项卡:

使用 Arthas 在 Spring 运行时获取配置值和配置来源

背景 众所周之,Spring / Spring Boot 应用的配置注入方式非常多: System Properties / System Env application.properties / application.yaml Spring Profile Spring Cloud Config 还有很多配置注入的方式你可以参阅 中文文档,可谓是令人眼花缭乱。 获取运行时具体配置 对于开发人员来说,在运行时怎样确定某个配置是否生效?它的具体值是什么? 通过 Arthas,只要一行命令就可以获取到。 例如,获取 server.port 的具体值: vmtool --action getInstances --className org.springframework.context.ConfigurableApplicationContext --express 'instances[0].getEnvironment().getProperty("server.port")'@String[7001] 获取具体的配置来源 但是这个配置是从哪里来的? 对于 spring boot 应用,可以打开一个新的 terminal 窗口,执行 telnet 127.0.0.1 3658 连接上Arthas。 直接 watch 下面的函数。 在原来窗口用上面的 vmtool 命令来获取 server.port 的值。 从 watch 返回结果中可以看到,server.port 值来源于 application.yml: watch org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource findConfigurationPropertyPress Q or Ctrl+C to abort.Affect(class count: 1 , method count: 2) cost in 217 ms, listenerId: 5method=org.

在 Spring Boot 中嵌入 Keycloak 服务器

1、概览 Keycloak 是由 Red Hat 管理和在 Java 中由 JBoss 开发的开源身份和访问管理解决方案。 本文将带你了解如何在 在 Spring Boot 中嵌入 Keycloak 服务器,这样就能轻松启动预配置的 Keycloak 服务器。 Keycloak 也可以作为 独立服务器 运行,但需要下载并通过管理控制台进行设置。 2、Keycloak 预配置 服务器包含一组 Realm,每个 Realm 都是用户管理的独立单元。要对其进行预配置,我们需要指定一个 JSON 格式的 Realm 定义文件。 使用 Keycloak Admin 控制台 配置的所有内容都以 JSON 格式进行持久化。 我们的授权服务器将使用名为 baeldung-realm.json 的 JSON 文件进行预配置。文件中的几个相关配置如下: users:默认用户是 john@test.com 和 mike@other.com;对应的凭证也在这里。 clients:定义一个 ID 为 newClient 的客户端 standardFlowEnabled:设置为 true,激活 newClient 的授权码(Authorization Code)授权模式。 redirectUris:newClient 在成功验证后将重定向到的服务器 URL webOrigins:置为 +,为所有 redirectUris 的 URL 提供 CORS 支持 Keycloak 服务器会默认签发 JWT Token,因此无需为此进行单独配置。接下来看看 Maven 的配置。

Spring 中的 @ConditionalOnProperty 注解

1、概览 本文将带你了解 Spring 中 @ConditionalOnProperty 注解的作用和用法。 2、@ConditionalOnProperty 的作用 通常,在开发基于 Spring 的应用时,需要根据配置属性是否存在,或者配置属性有指定的值来有条件地创建一些 Bean。 例如,我们需要注册一个 DataSource Bean,并且要根据属性值设置为 prod 还是 test 来创建生产数据库或测试数据库。 这正是 @ConditionalOnProperty 注解的用武之地。 简而言之,@ConditionalOnProperty 只有在环境属性存在且具有指定值的情况下才会启用 Bean 注册。默认情况下,指定的属性必须已定义且等于指定的值。 熟悉了 @ConditionalOnProperty 注解的用途后,接着来深入了解一下如何使用。 3、@ConditionalOnProperty 注解实践 开发一个基本的电子邮件通知系统来示范 @ConditionalOnProperty 的使用。 首先,创建一个简单的服务来发送通知消息。 定义 NotificationSender 接口: public interface NotificationSender { String send(String message); } 接下来,提供一个 NotificationSender 接口的实现来发送电子邮件: public class EmailNotification implements NotificationSender { @Override public String send(String message) { return "Email Notification: " + message; } } 现在,来看看如何使用 @ConditionalOnProperty 注解。

Spring 中的 @DynamicPropertySource 注解

1、概览 当代应用通常需要连接到各种外部服务,如 PostgreSQL、Apache Kafka、Cassandra、Redis 和其他外部 API。 本文将带你了解 Spring 如何通过引入动态属性(@DynamicPropertySource)来帮助测试此类应用。 2、问题:动态属性 假设我们正在开发一个使用 PostgreSQL 作为数据库的应用。 创建 JPA 实体: @Entity @Table(name = "articles") public class Article { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private String title; private String content; // get、set 省略 } 我们需要编写测试来确保应用按预期运行,由于该测试需要与真实数据库创建连接,我们应该事先建立一个 PostgreSQL 实例。 在测试执行过程中,有不同的方法来设置此类基础工具。事实上,这类解决方案主要有三类: 专门为测试设置一个单独的数据库服务器 使用一些轻量级的、测试专用的替代品,如 H2 让测试本身管理数据库的生命周期 由于未区分测试环境和生产环境,与使用 H2 等测试替身相比,有更好的选择。第三个选项不仅可以与真实数据库一起使用,还可以为测试提供更好的隔离性。此外,借助 Docker 和 Testcontainers 等技术,实现第三个选项非常容易。 如果使用 Testcontainers 等技术,测试流程如下: 在所有测试前设置 PostgreSQL 等组件。通常,这些组件会监听随机端口。 运行测试。 卸载组件。 如果 PostgreSQL 容器每次都监听随机端口,那么我们就应该以某种方式动态设置和更改 spring.datasource.url 配置属性。基本上,每个测试都应该有自己的配置属性版本。 当配置是静态的时候,可以使用 Spring Boot 的配置管理工具轻松地对其进行管理。但是,当我们面对的是动态配置时,同样的任务就会变得比较麻烦。

隐藏 Swagger API 文档中的端点

1、概览 在 Spring Boot 中使用 Swagger 文档时,有时候需要隐藏端点。最常见的情况就是,该端点还在开发中。或者是有一些内部端点,不想暴露给用户。 本文将带你了解如何在 Swagger API 文档中隐藏端点。 2、使用 @ApiIgnore 隐藏端点 可以在 Handler 方法上添加 @ApiIgnore 注解来隐藏端点: @ApiIgnore @ApiOperation(value = "This method is used to get the author name.") @GetMapping("/getAuthor") public String getAuthor() { return "Umang Budhwar"; } 3、使用 @ApiOperation 隐藏端点 也可以使用 @ApiOperation 来隐藏端点: @ApiOperation(value = "This method is used to get the current date.", hidden = true) @GetMapping("/getDate") public LocalDate getDate() { return LocalDate.now(); } 将 @ApiOperation 注解的 hidden 属性设置为 true,即可使 Swagger 忽略该端点。

Spring 中的事件(Event)机制

1、Spring 事件机制 有的人可能会觉得 Spring 中的事件机制很神奇,一个地方发消息,另一个地方收消息,跟 MQ 一样。其实,Spring 中的事件本质上就是观察者模式的应用。事件有其便利的一面,但是用多了也容易导致混乱,所以在实际项目中,我们还是要谨慎选择是否使用 Spring 事件。 2、简单实践 先用一个简单的案例,来让大家了解一下 Spring 中事件的应用。 事件发布流程中,有三个核心概念,它们之间的关系如下图: 事件源(ApplicationEvent):这个就是你要发布的事件对象。 事件发布器(ApplicationEventPublisher):这是事件的发布工具。 事件监听器(ApplicationListener):这个相当于是事件的消费者。 以上三个要素,事件源和事件监听器都可以有多个,事件发布器(通常是由容器来扮演)一般来说只有一个。 接下来,让我们通过一个简单的案例来演示一下 Spring 中事件的用法。 首先,我们需要自定义一个事件对象,自定义的事件继承自 ApplicationEvent 类,如下: public class MyEvent extends ApplicationEvent { private String name; public MyEvent(Object source, String name) { super(source); this.name = name; } @Override public String toString() { return "MyEvent{" + "name='" + name + '\'' + "} " + super.toString(); } } 这里只额外定义了一个 name 属性,如果大家在事件发送的时候需要传递的数据比较多,那么就可以在这里定义更多的属性。 在具体实践中,事件源并非一定要继承自 ApplicationEvent,事件源也可以是一个普通的 Java 类,如果是普通的 Java 类,系统会自动将之封装为一个 PayloadApplicationEvent 对象去发送。

Keycloak 自定义用户属性

1、概览 Keycloak 是第三方授权服务器,负责管理我们 Web 或移动应用的用户。 它提供了一些默认属性,例如名字、姓氏和电子邮件,用于存储任何给定用户的信息。但是很多时候,这些属性是不够的,我们可能需要添加一些特定于我们应用的额外用户属性。 本文将带你了解如何在 Keycloak 授权服务器中添加自定义用户属性,并在基于 Spring 的后端中访问它们。 2、独立服务器 2.1、添加自定义用户属性 基于上文 “Spring Boot 整合 Keycloak” 中的 Keycloak 服务器。 第一步是进入 Keycloak 的管理控制台。 在 Keycloak 发行版的 bin 文件夹中运行如下命令来启动服务器: kc.bat start-dev 然后,进入 Web 管理控制台 http://localhost:8180/auth/admin,输入凭证:initial1 / zaq1!QAZ 。 接下来,点击 “Manage” 选项卡下的 “Users”: 在这里,可以看到 之前(上一篇文章)添加的用户:user1。 点击 “ID”,然后转到 “Attributes” 选项卡,添加一个新的属性,即表示出生日期的 “DOB”: 点击 “Save” 后,自定义属性就会添加到用户信息中。 接下来,将此属性作为自定义 Claim 添加到映射中,以便它在用户 Token 的 JSON Payload 中可用。 为此,需要进入管理控制台的 “应用客户端”。回想一下 之前 创建的客户端 login-app: 点击它,然后选择 “Client scopes” 选项卡。在 “Client scopes” 页面点击 “login-app-dedicated” 链接,进入 “Mappers” 选项卡。点击 “Configure a new mapper”,选择 “User Attribute” 创建新 mapper: