04_学习springdoc与oauth结合_简述
文章目录
- 1 前言
- 2 基本结构
- 3 需要做的配置 简述
- 4 需要做的配置 详述
- 4.1 backend-api-gateway 的配置
- 4.1.1 application.yml
- 4.2 backend-film 的配置
- 4.2.1 pom.xml 引入依赖
- 4.2.2 application.yml 的配置
- 4.2.3 Spring Security 资源服务器的配置类 MyResourceServerConfig
- 4.2.4 Springdoc 配置类 MySpringdocConfig
- 4.3 backend-cinema 的配置
- 4.3.1 Feign JWT 中继的拦截器
- 4.4 auth-gateway 的配置
- 4.4.1 application.yml
- 4.5 auth-server 的配置
- 4.5.1 向数据库表 oauth2_registered_client 添加 client 信息
- 5 最后差点忘了😂 API 接口的 swagger 注解也需要修改
- 6 结语
1 前言
在上一篇文章 《03_学习springdoc与微服务结合_简述》 的基础上,我们可以更进一步,把 认证授权中心 Spring Authorization Server 也拽进来,让事情变得更复杂一些。😂也许事情总是会从简单到复杂。
本文的代码,是基于 Spring Boot 3.1.3、Spring Cloud 2022.0.4、Java 17 构建的。
2 基本结构
基本的组成部分 图示:

springdoc swagger ui 使用 oauth 认证和授权的流程,时序图:

3 需要做的配置 简述
如下图,一共有 5 块儿地方(红字所示),需要做配置:

简单说明一下,因为上一篇文章《03_学习springdoc与微服务结合_简述》已经对上图左侧 电影APP后台系统,做了 springdoc 与各个服务的整合,所以现在只剩下它们与 oauth2 的整合,以及 JWT 在 feign 的中继。
上图右侧的认证授权中心,是基于 spring-boot-starter-oauth2-authorization-server 写的,至于它如何配置,可以参考 Spring 官网 https://spring.io/projects/spring-authorization-server ,这里不再赘述。配置好之后,我们就只需要向数据库表添加 client 信息了。
注意,127.0.0.1 和 192.168.0.111 其实都是我本机 localhost,但是因为 eureka-server 和 spring authorization server 的缘故(🤣我也不知道具体什么原因),如果都用 127.0.0.1 ,则 spring authorization server 的反应会不正常。
4 需要做的配置 详述
有了上面的简述,接下来我们按照图片,把需要做的配置,一个个详细地说明。
4.1 backend-api-gateway 的配置
4.1.1 application.yml
springdoc:swagger-ui:urls:- name: backend-cinemaurl: /cateye/backend-cinema/v3/api-docs- name: backend-filmurl: /cateye/backend-film/v3/api-docs# 重点是下面这一句# 指定 swagger oauth2 授权码流程的 redirectUrl , 默认是 /swagger-ui/oauth2-redirect.html# 这里选择了 backend-film 服务的 swagger redirectUrl# 其实选择 backend-cinema 的也可以. 随便指定一个能访问的就行oauth2-redirect-url: http://127.0.0.1:8080/cateye/backend-film/swagger-ui/oauth2-redirect.htmlcache:disabled: true
4.2 backend-film 的配置
4.2.1 pom.xml 引入依赖
<!-- oauth 资源服务 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
4.2.2 application.yml 的配置
spring:application:name: backend-filmsecurity:oauth2:# 授权服务器的 URLresourceserver:jwt:# 这个是 auth-gateway. 在 auth-server 里面,我设置的 issuer-uri 也是直接访问网关issuer-uri: http://192.168.0.111:9090# springdoc 的配置
springdoc:swagger-ui:oauth:# oauth 客户端的 clientId 和 clientSecretclientId: cat-eye-background-backend-film-swaggerclientSecret: passwordcache:disabled: true# 授权码流程的2个urloAuthFlow:authorizationUrl: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/oauth2/authorizetokenUrl: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/oauth2/token
4.2.3 Spring Security 资源服务器的配置类 MyResourceServerConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;@EnableWebSecurity
@Configuration
public class MyResourceServerConfig {/*** 资源服务器的 spring security 过滤器链*/@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests(authorize -> authorize// 放行 swagger 相关的页面.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()// 演员相关的权限控制.requestMatchers("/actor/search-by-id/**","/actor/search-page").hasAuthority("SCOPE_actor.read").requestMatchers("/actor/**").hasAuthority("SCOPE_actor.write")// 影片相关的权限控制.requestMatchers("/film/search-by-id/**","/film/search-page","/film/search-batch").hasAuthority("SCOPE_film.read").requestMatchers("/film/**").hasAuthority("SCOPE_film.write")// 剩余的都至少需要认证.anyRequest().authenticated()).oauth2ResourceServer((oauth2) -> oauth2.jwt(Customizer.withDefaults()));return http.build();}
}
4.2.4 Springdoc 配置类 MySpringdocConfig
😂因为要配置的挺多,我们就使用注解形式的配置吧,写起来简洁明了一些。下面配置的是 OAuth2 的授权码流程。
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
import io.swagger.v3.oas.annotations.security.*;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.Scopes;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@OpenAPIDefinition(info = @Info(title = "电影APP后台-影片模块 API", version = "1.0.0", description = "包含了影片和演员相关的 API",license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0")))
@SecurityScheme(name = "security_auth", type = SecuritySchemeType.OAUTH2,flows = @OAuthFlows(authorizationCode = @OAuthFlow(authorizationUrl = "${springdoc.oAuthFlow.authorizationUrl}",tokenUrl = "${springdoc.oAuthFlow.tokenUrl}",scopes = {@OAuthScope(name = "actor.read", description = "演员读权限"),@OAuthScope(name = "actor.write", description = "演员写权限"),@OAuthScope(name = "film.read", description = "影片读权限"),@OAuthScope(name = "film.write", description = "影片写权限")})))
@Configuration
public class MySpringdocConfig {
}
效果如下图:

4.3 backend-cinema 的配置
4.3.1 Feign JWT 中继的拦截器
本文参考自 《JWT如何在OpenFeign调用中进行令牌中继》https://juejin.cn/post/7023246872147918885 ,把用到的代码拷贝如下:
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Component
public class FeignBearerTokenRequestInterceptor implements RequestInterceptor {private static final Pattern BEARER_TOKEN_HEADER_PATTERN = Pattern.compile("^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$",Pattern.CASE_INSENSITIVE);@Overridepublic void apply(RequestTemplate template) {final String authorization = HttpHeaders.AUTHORIZATION;ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (Objects.nonNull(requestAttributes)) {String authorizationHeader = requestAttributes.getRequest().getHeader(HttpHeaders.AUTHORIZATION);Matcher matcher = BEARER_TOKEN_HEADER_PATTERN.matcher(authorizationHeader);if (matcher.matches()) {// 清除token头 避免传染template.header(authorization);template.header(authorization, authorizationHeader);}}}
}
4.4 auth-gateway 的配置
4.4.1 application.yml
spring:application:name: auth-gatewaycloud:gateway:# CORS配置globalcors:cors-configurations:'[/**]':allowedOrigins: "*"allowedMethods:- GET- HEAD- POST- PUT- DELETE- TRACE- OPTIONS- PATCHallowedHeaders: "*"
4.5 auth-server 的配置
4.5.1 向数据库表 oauth2_registered_client 添加 client 信息
如下图:

可以在 auth-server 的 test 类里面,通过代码 insert 一行 client 信息,如下:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mariadb.jdbc.MariaDbDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;import java.sql.SQLException;
import java.util.UUID;public class SecurityTest {@Testpublic void addRegisteredClient() throws SQLException {MariaDbDataSource dataSource = new MariaDbDataSource();dataSource.setUrl("jdbc:mariadb://192.168.56.1:3306/cateye?autoReconnect=true&allowMultiQueries=true");dataSource.setUser("sjzadmin");dataSource.setPassword("P_sjz123");JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);JdbcRegisteredClientRepository repository = new JdbcRegisteredClientRepository(jdbcTemplate);RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("cat-eye-background-backend-cinema-swagger")// 注意 密码不能重复, 所以可以稍稍修改下密码, 然后再直接 SQL 改回来.clientSecret("1$2a$10$To/16R/ZmbYlSqvpb9G2OOwZPrGO7VC52WLQUPtVMciymzujN/s4i")// 注意 swagger 的 client_id client_secret 是通过 POST 请求的请求体过来的// 而不是在 HTTP Basic 里面, 所以下面要用 CLIENT_SECRET_POST.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).redirectUri("http://127.0.0.1:8080/cateye/backend-film/swagger-ui/oauth2-redirect.html").scope(OidcScopes.OPENID).scope(OidcScopes.PROFILE).scope("movie.hall.read").scope("movie.hall.write").scope("film.read").build();repository.save(client);RegisteredClient dbClient = repository.findByClientId("cat-eye-background-backend-cinema-swagger");Assertions.assertNotNull(dbClient);}
}
5 最后差点忘了😂 API 接口的 swagger 注解也需要修改
@Tag(name = "02_影片", description = "影片 API")
@ApiResponses(@ApiResponse(responseCode = "200", description = "接口请求成功"))
public interface FilmApi {// 注意,接口的 Operation 注解里面要加 security 属性// 其 name 就是 4.2.4 小节 MySpringdocConfig 类里面定义的// @SecurityScheme(name = "security_auth")@Operation(summary = "分页查询影片", security = @SecurityRequirement(name = "security_auth"))@RequestMapping(value = "/film/search-page", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)JsonResult<PageInfo<FilmBriefResp>> searchPage(@Valid @RequestBody PageReq<FilmSearchPageReq> pageReq);
}
6 结语
因本文涉及的代码是学习用的小项目中的代码,而生产环境可能更加复杂吧,所以本文仅供参考😁
感谢阅读~
相关文章:
04_学习springdoc与oauth结合_简述
文章目录 1 前言2 基本结构3 需要做的配置 简述4 需要做的配置 详述4.1 backend-api-gateway 的配置4.1.1 application.yml 4.2 backend-film 的配置4.2.1 pom.xml 引入依赖4.2.2 application.yml 的配置4.2.3 Spring Security 资源服务器的配置类 MyResourceServerConfig4.2.4…...
【设计模式】单例模式的7种实现方法
一、饿汉式-线程安全 线程安全,但无法实现实例懒加载策略 /*** 饿汉式* author CC* version 1.0* since2023/10/12*/ public class Singleton {private static final Singleton singleton new Singleton();private Singleton() {}public static Singleton getSin…...
AlphaPose Pytorch 代码详解(一):predict
前言 代码地址:AlphaPose-Pytorch版 本文以图像 1.jpg(854x480)为例对整个预测过程的各个细节进行解读并记录 python demo.py --indir examples/demo --outdir examples/res --save_img1. YOLO 1.1 图像预处理 cv2读取BGR图像 img [480,…...
日常学习记录随笔-zabix实战
使用zabix结合 实现一套监控报警装置 不管是web开发还是大数据开发 我们的离线项目还是实时项目也好,都需要把我们的应用提交到我们服务器或者容器中去执行 整个应用过程中怎么保证线上整体环境的稳定运行 监控很重要 现在比较主流的就是 普罗米修斯以及zabix 我要做…...
vw+rem自适应布局
开发过程中,我们希望能够直接按照设计图来开发,不管设计图是两倍还是三倍图,能够直接写设计图尺寸而不需要换算,同时有高质的设计图还原度,想想都比较爽。 这里介绍一种使用vw和rem来布局的方案。 该方案思路主要是&am…...
【MySql】mysql之MHA高可用配置及故障切换
一、MHA概念 MHA(Master High Availability)是一套优秀的Mysql高可用环境下故障切换和主从复制的软件。 MHA的出现就是解决Mysql单点的问题。 Mysql故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过程中最大程…...
如何在 Spring Boot 中进行数据备份
在Spring Boot中进行数据备份 数据备份是确保数据安全性和可恢复性的关键任务之一。Spring Boot提供了多种方法来执行数据备份,无论是定期备份数据库,还是将数据导出到外部存储。本文将介绍在Spring Boot应用程序中进行数据备份的不同方法。 方法1: 使用…...
为Yolov7环境安装Cuba匹配的Pytorch
1. 查看Cuba版本 方法一 nvidia-smi 找到CUDA Version 方法二 Nvidia Control Panel > 系统信息 > 组件 > 2. 安装Cuba匹配版本的PyTorch https://pytorch.org/get-started/locally/这里使用conda安装 conda install pytorch torchvision torchaudio pytorch-cu…...
SpringBoot基于jackson对象映射器扩展mvc框架的消息转换器
在SpringBoot中,可以基于jackson对象映射器扩展mvc框架的消息转换器 具体步骤如下: 1、创建对象映射器: package com.java.demo.common;import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.datab…...
计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度(matlab代码)
目录 1 主要内容 系统结构 CCPP-P2G-燃气机组子系统 非线性处理缺陷 2 部分代码 3 程序结果 4 程序链接 1 主要内容 该程序参考《计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度》模型,主要实现的是计及电转气协同的含碳捕集与垃圾焚烧虚拟电厂优化调度…...
【低代码表单设计器】:创造高效率的流程化办公!
当前,有不少用户朋友对低代码表单设计器挺感兴趣。其实,如果想要实现提质增效的办公效率,创造一个流程化办公,那么确实可以了解低代码技术平台。流辰信息作为服务商,拥有较强的自主研发能力,根据市场的变化…...
26、类型别名
类型别名 顾名思义,其实就是类型类型起别名(新起一个名字) demo: type Name string; type NameConsole () > string; type NameUnite Name | NameConsole; function getName(n: NameUnite): Name {if( typeof n string)…...
nslookup命令查询指定域名或ingress地址对应的IP地址。举个例子
使用nslookup命令查询指定域名或ingress地址的IP地址时,可以按照以下方式进行操作: 对于域名查询: 复制代码 nslookup www.example.com 这将返回该域名对应的IP地址。 对于ingress地址查询: 复制代码 nslookup your-ingress-a…...
如何设计一个网络爬虫?
网络爬虫也被称为机器人或蜘蛛,它被搜索引擎用于发现网络上的新内容或更新内容。内容可以是网页、图片、视频、PDF文件等。网络爬虫开始时会收集一些网页,然后跟随这些网页上的链接收集新的内容。图9-1展示了爬取过程的可视化示例。 爬虫的作用ÿ…...
风储联合系统的仿真模型研究
摘要 风能是目前国内外应用较为广泛的一种绿色可再生能源,近几年我国风电产业的发展十分迅速。然后,越来越多的风力发电系统建并网,风力发电产生的电能受外界因素影响较大,具有一定的随机性和波动性,给并网后的电力系统…...
JS VUE 用 canvas 给图片加水印
最近写需求,遇到要给图片加水印的需求。 刚开始想的方案是给图片上覆盖一层水印照片,但是这样的话用户直接下载图片水印也会消失。 后来查资料发现用 canvas 就可以给图片加水印,下面是处理过程。 首先我们要确认图片的格式,我们通…...
主动配电网故障恢复的重构与孤岛划分matlab程序
微❤关注“电气仔推送”获得资料(专享优惠) 参考文档: A New Model for Resilient Distribution Systems by Microgrids Formation; 主动配电网故障恢复的重构与孤岛划分统一模型; 同时考虑孤岛与重构的配电网故障…...
2023C语言暑假作业day6
1.选择题 1 1、以下叙述中正确的是( ) A: 只能在循环体内和switch语句体内使用break语句 B: 当break出现在循环体中的switch语句体内时,其作用是跳出该switch语句体,并中止循环体的执行 C: continue语句的作用是:在执…...
java try 自动关闭流
Java Try自动关闭流实现步骤 在开始之前,我们先来了解一下整个实现过程的流程。下面的表格展示了实现"try自动关闭流"的步骤: 步骤 描述 1 创建需要操作的流对象 2 在try语句块中使用流对象 3 在try语句块中自动关闭流对象 接下来…...
WebDAV之π-Disk派盘 + 元思笔记
元思笔记是一款面向大众的卡片笔记软件,解决了笔记类软件的一个痛点:绝大多数人都很难坚持每天记一点东西。任何笔记工具,不论是纸笔还是电子,能够让人坚持记录就是好工具。 元思笔记是一款基于卢曼卡片盒的移动端卡片笔记软件;隐私优先,本地存储数据且支持云备份;丰富的…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
