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 结语

  因本文涉及的代码是学习用的小项目中的代码,而生产环境可能更加复杂吧,所以本文仅供参考😁

  感谢阅读~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/101877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp iosApp H5+本地文件操作(写入修改删除等)

h5 地址 html5plus 以csv文件为例&#xff0c;写入读取保存修改删除文件内容&#xff0c;传输文件等 1.save 文件保存 function saveCsv(data,pathP,path){// #ifdef APP-PLUSreturn new Promise((resolve, reject) > {plus.io.requestFileSystem( plus.io.PUBLIC_DOCUMEN…

WIN32API之PIPE管道

管道是进程用于通信的共享内存的一部分。 创建管道的过程是 管道服务器。 连接到管道的进程是 管道客户端。 一个进程将信息写入管道&#xff0c;另一个进程从管道读取信息。 本概述介绍如何创建、管理和使用管道。 命名管道是用于管道服务器与一个或多个管道客户端之间通信的…

vue打印功能

安装 vue3-print-nb yarn add vue3-print-nb //或 npm install vue3-print-nbmain.js中引入 vue3-print-nb import { createApp } from vue; import App from ./App.vue; const app createApp(App); // 打印插件 import print from vue3-print-nb app.use(print) //页面内引…

【Docker 内核详解】namespace 资源隔离(一):进行 namespace API 操作的 4 种方式

namespace 资源隔离&#xff08;一&#xff09;&#xff1a;进行 namespace API 操作的 4 种方式 1.通过 clone() 在创建新进程的同时创建 namespace2.查看 /proc/[pid]/ns 文件3.通过 setns() 加入一个已经存在的 namespace4.通过 unshare() 在原先进程上进行 namespace 隔离5…

Webapck 解决:[webpack-cli] Error: Cannot find module ‘vue-loader/lib/plugin‘ 的问题

1、问题描述&#xff1a; 其一、报错为&#xff1a; [webpack-cli] Error: Cannot find module vue-loader/lib/plugin 中文为&#xff1a; [webpack-cli] 错误&#xff1a;找不到模块“vue-loader/lib/plugin” 其二、问题描述为&#xff1a; 在项目打包的时候 npm run …

c++视觉图像----扩充边界

图像扩充边界 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp>int main() {// 读取图像cv::Mat image cv::imread("1.jpg", cv::IMREAD_COLOR);if (image.empty()) {std::cerr << "Could not open or find the imag…

Java项目调用Python脚本(基于idea)

前期准备 1.首先需要在本地环境中安装配置python环境 Python(含PyCharm及配置)下载安装以及简单使用(Idea) 博主本次使用python版本为py3.7.3 2.idea安装python插件 位置&#xff1a;File->Settings->Plugins->python->安装后重启即可 3.引入jython依赖 &l…

力扣 -- 1312. 让字符串成为回文串的最少插入次数

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int minInsertions(string s) {int ns.size();vector<vector<int>> dp(n,vector<int>(n));//无需初始化//填表for(int in-1;i>0;i--){for(int ji;j<n;j){//状态转移方程if(s[i]s[…

如何在 Spring Boot 中进行数据备份

在Spring Boot中进行数据备份 数据备份是确保数据安全性和可恢复性的关键任务之一。Spring Boot提供了多种方法来执行数据备份&#xff0c;无论是定期备份数据库&#xff0c;还是将数据导出到外部存储。本文将介绍在Spring Boot应用程序中进行数据备份的不同方法。 方法1: 使用…

【深度学习实验】循环神经网络(一):循环神经网络(RNN)模型的实现与梯度裁剪

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 数据处理 2. rnn 测试 3. grad_clipping 4. 代码整合 经验是智慧之父&#xff0c;记忆是智慧之母。 ——谚语 一、实验介绍 本实验介绍了一个简单的循环神经网络…

如何优化前端图像和多媒体资源?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

电子书制作软件Vellum mac中文版特点

Vellum mac是一款专业的电子书制作软件&#xff0c;它可以帮助用户将文本文件转换为高质量的电子书&#xff0c;支持多种格式&#xff0c;包括EPUB、MOBI、PDF等。Vellum具有直观的用户界面和易于使用的工具&#xff0c;可以让用户快速地创建和发布电子书。 Vellum mac软件特点…

追求极致性能!Qwik 1.0版本发布

前言 偶然发现 Qwik 这个 Node.js 后端框架&#xff0c;感觉非常新奇&#xff0c;它构建的网站&#xff0c;能够在谷歌的网站评测工具中跑出100分满分的成绩&#xff0c;而且还是移动端&#xff08;一般情况下&#xff0c;移动端分值要低于PC端&#xff09;&#xff01;不得不…

IDEA XML文件里写SQL比较大小条件

背景 最近开发的时候&#xff0c;有一个需求的查询需要支持范围查询[a,b)&#xff0c;并且查询的结果要求查询的范围含头端点不含尾端点。因为between…and…查询的范围是含头含尾的&#xff0c;因而不能使用。 因此打算直接使用>和<来比较实现&#xff0c;使用>的时…

【Redis】Set集合内部编码方式

内部编码 集合类型的内部编码有两种&#xff1a; intset&#xff08;整数集合&#xff09;&#xff1a;当集合中的元素都是整数并且元素的个数⼩于set-max-intset-entries配置&#xff08;默认512个&#xff09;时&#xff0c;Redis会选⽤intset来作为集合的内部实现&#xf…

与艺术同频!卡萨帝在海外崭露头角

在品牌全球化步伐日益加快的当下&#xff0c;高端品牌如何真正实现业务全球化、品牌全球化乃至用户圈层全球化&#xff1f; 作为国际高端家电引领者&#xff0c;卡萨帝今年以来在全球范围内展开了一系列的品牌布局活动。1月&#xff0c;卡萨帝于巴基斯坦召开品牌发布会&#x…

hyperf框架WebSocket 服务

1&#xff1a;安装 composer require hyperf/websocket-server2&#xff1a;配置 Server 修改 config/autoload/server.php&#xff0c;增加以下配置。 return [servers > [[name > ws,type > Server::SERVER_WEBSOCKET,host > 0.0.0.0,port > 9502,sock_typ…

分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测

分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于RF-Adaboost随机森林结合AdaBoost多输…

[JAVA版本] Websocket获取B站直播弹幕——基于直播开放平台

教程 B站直播间弹幕Websocket获取 — 哔哩哔哩直播开放平台 基于B站直播开放平台开放且未上架时&#xff0c;只能个人使用。 代码实现 1、相关依赖 fastjson2用于解析JSON字符串&#xff0c;可自行替换成别的框架。 hutool-core用于解压zip数据&#xff0c;可自行替换成别的…

手写Spring系列【一】IOC的简单实现笔记

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏&#xff1a;项目专栏 &#x1f4e7;如果文章知识点有错误的地方&#xff0c;…