在网关解析 JWT 并中继给其他服务
通过前面几篇文章我们已经实现了将网关作为资源服务器并在网关实现认证和授权,其他服务将是一个纯粹的微服务,那么我们将问一个问题其他微服务如何获取到已授权用户的用户信息?
通过前面几篇文章我们已经实现了将网关作为资源服务器并在网关实现认证和授权,其他服务将是一个纯粹的微服务,那么我们将问一个问题其他微服务如何获取到已授权用户的用户信息?
我们将要实现这样一个微服务系统,将 Spring Cloud Gateway 作为 OAuth2 的资源服务器,在 Gateway 实现集中的统一的鉴权功能,各个微服务之间的调用不再单独鉴权。系统的规划如下表所示
系统 | 端口 | 说明 |
---|---|---|
example-auth | 9090 | 认证与授权服务 |
example-eureka | 8761 | 服务注册中心 |
example-gateway | 8080 | 服务网关 |
example-user | 8081 | 用户服务 |
example-product | 8082 | 商品服务 |
example-order | 8083 | 订单服务 |
example-common | - | 公共模块 |
example-auth 是一个独立的服务,它不会向服务注册中心注册自己,其他的服务,包括 example-gateway,均需要向服务注册中心注册自己。
我们有一个使用 Spring Cloud 技术栈开发的简单的商城项目 acomma/shop tag:spring-boot-2,现在要将它构建成 Docker 镜像并以容器的方式运行起来。
Spring Security OAuth 的生命周期已经结束,现在推荐使用 Spring Authorization Server。
Spring Security OAuth 的生命周期已经结束,官方已经删除它的文档,现在推荐使用 Spring Authorization Server,但是还是有很多老项目在继续使用 Spring Security OAuth,学习它仍然是必要的。虽然官方文档已经删除了,但是找到了一篇较早时间的翻译 Spring Security OAuth2 开发指南,可以作为实践的基础。网络上也有很多如何使用它的文章,这篇文章是自己实践的一点记录。
备注:Knife4j 通过 com.github.xiaoymin.knife4j.spring.extension.Knife4jOpenApiCustomizer
类的 addOrderExtension
方法给 Tag
类应用 @ApiSupport
注解的 order
属性。
在我们的一个项目中使用了 Knife4j 来显示 Swagger 的文档,具体的依赖如下
1 | <dependency> |
同时我们有两个 Controller,它们分别是
1 | @RestController |
默认情况下,在 Knife4j 的页面中“角色管理”显示在了“用户管理”的前面。我们期望“用户管理”显示在“角色管理”的前面。为了达到这个目的我们使用了 Knife4j 提供的注解 @ApiSupport
,修改后的代码如下所示
1 | @RestController |
但是并没有什么效果,“用户管理”并没有显示在“角色管理”的前面,即 @ApiSupport
注解没有生效。
我们有一个项目使用了 Knife4j,依赖的版本为
1 | <dependency> |
这个版本的 Knife4j 使用了 SpringDoc,其获取 Swagger 配置的地址为 /v3/api-docs/swagger-config
,获取文档的地址为 /v3/api-docs
,如果项目有多个分组,获取单个分组,比如分组“1-动物”,的文档的地址为 /v3/api-docs/1-动物
。
在项目部署时在项目的前面放置了一台 Nginx 反向代理服务器,配置了当访问路径为 /example
时会将请求转发到我们自己的项目
1 | location /example/ { |
当访问 http://localhost/example/doc.html
时,Knife4j 能正常的访问 Swagger 的配置,即 http://localhost/example/v3/api-docs/swagger-config
,但是无法访问 http://localhost/v3/api-docs/1-动物
,因此无法打开 Knife4j 文档页面。
首先创建一个 Spring Boot 项目,然后创建一个实体类 User
,它有两个字段姓名 name
和生日 birthday
,其中 birthday
的类型是 OffsetDataTime
1 | @Data |
最后创建对应的控制器 UserController
,GET 请求的第二种形式将参数封装成了对象
1 | @RestController |
我们要实现接收前端传递过来的形如 yyyy-MM-dd HH:mm:ss
的字符串并自动将它转换为能够使用 OffsetDateTime
类型。
在 SpringBoot 应用中可以使用以下几种方式来控制是否返回值为空的字段
application.yml
中配置全局自动忽略 1 | spring: |
@JsonInclude(JsonInclude.Include.NON_NULL)
Jackson2ObjectMapperBuilderCustomizer
定制器 1 | @Bean |
JacksonObjectMapperConfiguration
自定义一个 ObjectMapper
,覆盖默认的定义 1 | @Bean |
这 4 种方式要么是全局的要么是局部的,它们都是一次性的,设置后就不能改变,每次请求都会返回相同的结果。现在我们要实现根据请求参数中是否包含某个值动态的设置是否返回值为空的字段,具体的说我们要根据请求头中是否包含 X-Include-Non-Null
来控制是否返回值为空的字段。