04_学习springdoc与oauth结合_简述

news2024/11/20 13:39:10

文章目录

  • 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-cinema
        url: /cateye/backend-cinema/v3/api-docs
      - name: backend-film
        url: /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.html
  cache:
    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-film
  security:
    oauth2:
      # 授权服务器的 URL
      resourceserver:
        jwt:
          # 这个是 auth-gateway. 在 auth-server 里面,我设置的 issuer-uri 也是直接访问网关
          issuer-uri: http://192.168.0.111:9090

# springdoc 的配置
springdoc:
  swagger-ui:
    oauth:
      # oauth 客户端的 clientId 和 clientSecret
      clientId: cat-eye-background-backend-film-swagger
      clientSecret: password
  cache:
    disabled: true
  # 授权码流程的2个url
  oAuthFlow:
    authorizationUrl: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/oauth2/authorize
    tokenUrl: ${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 过滤器链
     */
    @Bean
    public 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);

    @Override
    public 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-gateway
  cloud:
    gateway:
      # CORS配置
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - HEAD
              - POST
              - PUT
              - DELETE
              - TRACE
              - OPTIONS
              - PATCH
            allowedHeaders: "*"

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 {
    @Test
    public 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.coloradmin.cn/o/1081345.html

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

相关文章

代数——第3章——向量空间

第三章 向量空间(Vector Spaces) fmmer mit den einfachsten Beispielen anfangen. (始终从最简单的例子开始。) ------------------------------David Hilbert 3.1 (R^n)的子空间 我们的向量空间的基础模型(本章主题)是n 维实向量空间 的子空间。我们将在本节讨论它。…

以全新的视角审视重构——世界软件大师“鲍勃大叔”作序推荐

编程不只是写代码&#xff0c;更是一门艺术。编写优雅代码是一种极致追求&#xff0c;这需要一种极客精神才可以达到。高质量的代码不仅可以增加代码可读性&#xff0c;还可以确保所写的代码能够高质量运行和高效维护。 编程也是一门沟通语言&#xff0c;是团队沟通的方式。对代…

计算机毕业设计选题推荐-springboot 企业在线培训系统

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

JUC并发编程(二):线程相关知识点

1.背景 实现编发编程的主要手段就是多线程。线程是操作系统里的一个概念。接下来先说说两者的定义、联系与区别。 1.1 进程和线程的区别 进程 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。系统运行一个程序即是一个进程从…

比特大陆:全员工资停发!昔日的“矿机一哥”遇现金流危机?

近日&#xff0c;一则关于比特大陆暂缓发放9月份全体员工部分工资的消息在网上流传。比特大陆对员工称公司营运现金流尚未转正&#xff0c;尤其是部矿(部署矿机进矿场)进度严重不达标&#xff0c;决定暂缓发放9月份全体员工部分公司&#xff0c;10月7日后视情况发放。 脉脉上多…

Unity基础课程之物理引擎6-关于物理材质的使用和理解

每个物体都有着不同的摩擦力。光滑的冰面摩擦力很小&#xff0c;而地毯表面的摩擦力则很大。另外每种材料也有着不同的弹性&#xff0c;橡皮表面的弹性大&#xff0c;硬质地面的弹性小。在Unity中这些现象都符合日常的理念。虽然从原理上讲&#xff0c;物体的摩擦力和弹性有着更…

利用异常实现短期hook

场景1 调用目标call 需要跳过某些判断或者函数 场景2 目标call 只需要部分指令执行 大概实现技术 设置线程上下文设置drX寄存器 实现硬件执行断点 主动调用目标call 通过硬件断点获取寄存器或修改eip 以上实现不改变crc且不通过驱动实现。只对当前执行线程有效&#xff…

ubuntu离线编译安装cmake 3.22.5(could not fonud OPENSSL) and cmake-versinon查不到版本问题

1、首先去cmake官网下载压缩包,例如: cmake-3.22.5.tar.gz 2、拉到ubuntu进行解压: tar -zxcf cmake-3.22.5.tar.gz 3、cd 进入目录 cd cmake-3.22.5 4、执行configure可执行文件 ./configure 如果在编译过程中出现报错:Could NOT findOpenSSL,原因可能是缺少ssl库 按…

第四节(1):EXCEL中判断一个WORD文件是否被打开

《VBA信息获取与处理》教程(10178984)是我推出第六套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。这部教程给大家讲解的内容有&#xff1a;跨应用程序信息获得、随机信息的利用、电子邮件的发送、VBA互联网…

如何计算一个结构体的大小?(C语言)

文章目录 写在前面1. 结构体的内存对齐2. 结构体大小的计算方式&#xff08;四步法&#xff09;3. 修改默认对齐数4. 内存对齐的意义5. 结构体设计技巧 写在前面 我们知道C语言中各种内置类型定义的变量都是有大小的&#xff0c;比如 int 类型的变量占4个字节&#xff0c;而像…

对一个变速器原理的分析

背景 原本是朋友在调试一个看起来比较新的变速器驱动&#xff0c;整体来说支持两种变速模式&#xff0c;一种是进程级&#xff0c;这种用了HOOK&#xff0c;中规中矩的实现&#xff0c;原理网上都有。另一种是”系统级内核全局变速“&#xff0c;这个模式初步看了下有些特殊&a…

猫头虎带您了解CSDN1024城市开发者大会分会场报名指南(文末送30元优惠券)

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

全链路压测:保障系统稳定性与性能的关键措施

随着互联网应用规模的不断扩大和用户对系统性能要求的提高&#xff0c;全链路压测成为保障系统稳定性和性能的关键环节。本文将介绍全链路压测的概念、重要性以及实施全链路压测的步骤和最佳实践&#xff0c;以帮助读者更好地理解和应用全链路压测技术。 一、全链路压测的概念与…

客服支持Chatbot提供即时回答,改善用户体验

大家在网上冲浪了那么久&#xff0c;一定对于客户支持Chatbot都有所了解。客户支持Chatbot就像真人客服一样&#xff0c;可以与人进行简单的对话&#xff0c;并针对人们的需求给出相应的回答。虽然有时候得到的答案并不怎么靠谱吧&#xff0c;但是总的还是比较节省人工的&#…

docker概念

docker 容器&#xff1a;就是提供在多台主机上运行的应用程序相同的运行环境。 docker的概念 是开源的容器&#xff0c;是由Go语言开发的&#xff0c;是容器里面运用的工具&#xff0c;他是一个轻量级的虚拟机&#xff0c;可以利用docker在多台主机上创建与运行容器。 docke…

矩阵剪辑系统源码----pc/手机端双开发

剪辑系统&#xff0c;剪辑矩阵系统&#xff0c;剪辑矩阵系统主要是针对抖音、快手、bili平台的一个工具&#xff0c;今天就来给大家交流一下这 个产品的主要功能以及构成。剪辑矩阵系统&#xff0c;矩阵剪辑系统源码-这产品主要功能就是一个视频剪辑功能&#xff0c;这个视频剪…

深入解析:探索Nginx与Feign交锋的背后故事 - 如何优雅解决微服务通信中的`301 Moved Permanently`之谜!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

2023年中国数据存储市场现状及发展前景预测分析

中商情报网讯&#xff1a;当前&#xff0c;新一代信息技术快速发展推动信息产业发生了重大变革&#xff0c;数据存储行业将很快成为信息领域一个重要的产业分支。生成式人工智能催生算力需求&#xff0c;各种新兴应用场景对数据存储的容量、效率、流动性和安全性等方面提出了更…

快速入门C++

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 我们学习了C语言&#xff0c;有了C语言的底子就更容易学习C&#xff0c;今天让我们认识一下C&#xff0c;并了解分析一下C。 目录 什么是C 为什么会出现C C的发展史 C与C语言的区别 …

漫画:大模型用于腾讯广告,难在哪?

&#xff08;一&#xff09;关键词&#xff1a;三大套路 大模型火了&#xff0c;大模型的套路也火了。 套路一&#xff1a; 但凡有点科技含量的公司&#xff0c; 没个大模型都对不起“市值”和“估值”。 面子谁不要&#xff1f; 那用开源。 套路二&#xff1a; 说早有布局&…