余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

响应式 APP 使用 Spring Security(4) - 响应式应用程序和 OAuth 2

xiyangw 2022-11-24 16:50 79 浏览 0 评论

你现在可能想知道,我们是否可以在一个基于 OAuth 2 框架设计的系统中使用响应式应用程序。在本文中,我们将讨论如何将资源服务器实现为响应式应用程序。您将学习如何配置响应式应用程序,使其依赖于通过 OAuth 2 实现的身份认证方法。由于现在使用 OAuth 2 非常普遍,您可能会遇到需要将资源服务器应用程序设计为响应式服务器的需求。我创建了一个新项目,我们将实现一个响应式资源服务器应用程序。您需要在 pom.xml 中添加依赖项,如下面的代码片段所示:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

我们需要一个端点来测试应用程序,因此我们添加了一个控制器类。下一个代码片段展示了控制器类:

@RestController
public class HelloController {

  @GetMapping("/hello")
  public Mono<String> hello() {
    return Mono.just("Hello!");
  }
}

现在,示例中最重要的部分:安全配置。对于本例,我们将资源服务器配置为使用授权服务器公开的公钥进行令牌签名验证。这种方法与《动手操作:一个 OAuth 2 应用程序(2) - 配置 Keycloak 为授权服务器》中使用 Keycloak 作为授权服务器的方法相同。在这个示例中,我实际上使用了相同的配置服务器。您可以选择执行相同的操作,也可以实现自定义授权服务器,如《OAuth 2:实现授权服务器》所述。

要配置身份认证方法,我们使用 SecurityWebFilterChain,如 《响应式 APP 使用 Spring Security(3)》所述。但是我们没有使用 httpBasic() 方法,而是调用 oauth2ResourceServer() 方法。然后,通过调用 jwt() 方法,我们定义了使用的令牌类型,并且通过使用 Customizer 对象,我们指定了验证令牌签名的方式。在清单 12 中,您可以找到配置类的定义。

清单 12 配置类

@Configuration
public class ProjectConfig {

  @Value("${jwk.endpoint}")
  private String jwkEndpoint;

  @Bean
  public SecurityWebFilterChain securityWebFilterChain(
    ServerHttpSecurity http) {
   
    return http.authorizeExchange()
                  .anyExchange().authenticated()
               .and().oauth2ResourceServer()  //配置资源服务器认证方式
                  .jwt(jwtSpec -> { //指定验证令牌的方式
                    jwtSpec.jwkSetUri(jwkEndpoint);
                  })
               .and().build();

    }
}

以同样的方式,我们可以配置公钥,而不是指定公开公钥的 URI。唯一的更改是调用 jwtSpec 实例的 publicKey() 方法,并提供一个有效的公钥作为参数。您可以使用我们在《OAuth 2:实现资源服务器》和《OAuth 2 : 使用 JWT 和加密签名》中讨论的任何方法,其中我们详细分析了资源服务器验证访问令牌的方法。

接下来,我们更改 application.properties文件以添加密钥集被曝露的 URI 的值,以及将服务器端口更改为9090。 这样,我们允许 KeyCloak8080上运行。在下一个代码片段中, 您可以找到 application.properties 文件的内容:

server.port=9090
jwk.endpoint=http://localhost:8080/auth/realms/master/protocol/openid-connect/certs

让我们运行并证明应用程序具有我们想要的预期行为。我们使用本地安装的 Keycloak 服务器生成访问令牌:

curl -XPOST 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'username=bill' \
--data-urlencode 'password=12345' \
--data-urlencode 'client_id=fitnessapp' \
--data-urlencode 'scope=fitnessapp'

在 HTTP 响应体中,我们接收到如下所示的访问令牌:

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI...",
    "expires_in": 6000,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5c... ",
    "token_type": "bearer",
    "not-before-policy": 0,
    "session_state": "610f49d7-78d2-4532-8b13-285f64642caa",
    "scope": "fitnessapp"
}

使用访问令牌,我们像这样调用应用程序的 /hello 端点:

curl -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJMSE9zT0VRSmJuTmJVbjhQb VpYQTlUVW9QNTZoWU90YzNWT2swa1V2ajVVIn...' \
'http://localhost:9090/hello'

响应体是

Hello!

总结

  • 响应式应用程序在处理数据和与其他组件交换消息方面具有不同的风格。在某些情况下,响应式应用程序可能是更好的选择,比如我们可以将数据分割成单独的小段进行处理和交换。

  • 与任何其他应用程序一样,您还需要使用安全配置来保护响应式应用程序。Spring Security 提供了一组优秀的工具,您可以使用它们为响应式应用程序和非响应式应用程序应用安全配置。

  • 为了用 Spring Security 在响应式应用中实现用户管理,我们使用了 ReactiveUserDetailsService 契约。该组件的作用与 UserDetailsService 对于非响应式应用的作用相同:它告诉应用如何获取用户详细信息。

  • 要实现响应式 web 应用程序的端点授权规则,您需要创建一个 SecurityWebFilterChain 类型的实例,并将其添加到 Spring 上下文。您可以使用 ServerHttpSecurity 构建器创建 SecurityWebFilterChain 实例

  • 通常,用于定义授权配置的方法的名称与用于非响应式应用程序的方法的名称相同。但是,您会发现与响应式术语相关的一些小的命名差异。例如,不使用 authorizeRequests(),响应式应用程序对应的名称是 authorizeExchange()

  • Spring Security 还提供了一种方法来定义方法级的授权规则,称为响应式方法安全,它提供了在响应式应用程序的任何层应用授权规则的极大灵活性。这类似于我们对非响应式应用程序所称的全局方法安全。

  • 然而,对于非响应式应用程序,响应式方法安全并不像全局方法安全那样成熟。您已经可以使用 @PreAuthorize@PostAuthorize 注解,但是 @PreFilter@PostFilter 的功能还有待开发。

相关推荐

高效删除文件名中的指定内容,祛除烦恼

如何快速批量删除文件名中的指定字符?在电脑整理文件时,我们常常需要进行批量重命名操作。如果文件名中含有不必要或重复的字符,这将影响文件的识别和查找。因此,删除这些文字或字符是非常必要且有效的。本文将分...

你的手机是不是经常提示存储空间不足?Python帮你清理重复文件

  最近我的手机经常提示存储空间不足,主要是微信和QQ群里接收的文件太多了,平时也没怎么整理。我把这些文件从手机里拷出来,打算整理一下,把该删的文件都删掉,把要备份的文件分门别类存到电脑或网盘上。我突...

从零开始打造云端AI管理调度平台(四)如何设计主页_1

最近闲来无事,想着把自己工作正在做的一个项目做一个简单的分享与实战教程,该项目不困难但是由于涉及要素过多所以比较复杂。所以这里分享出来也是为了帮助新手小白能在实战当中快速了解python知识。主要内容...

「万能Python」-17-标准库OS_python2.7标准库

Python的库是指预先编写好的代码集合,可以用来处理特定的任务或实现特定的功能。Python的标准库提供了许多常用的标准库,无需安装引入使用。Python3的标准库提供了许多常用的功能,包括...

十多行代码生成原帖和临写对照图_几十行代码可以申请软著吗

介绍这个小工具把原帖和临写分解成多列对照的形式。输入原帖图片,和输入临写图片,生成对照图片。使用说明运行compare.py文件,输入参数为:原帖图片文件名,临写图片文件名,列数。python3co...

Python合集之目录操作(四)_python之文件操作大全

1.删除目录删除目录可以通过os模块提供的rmdir()函数实现。通过rmdir()函数删除目录时,只有当要删除的目录为空时才起作用。os.rmdir(path)path为要删除的目录,可以使用绝对路...

excel办公自动化,自动合并excel表格

平时时收到不同人反馈的excel表格,需要将其合并在一个excel中,每个excel打开复制粘贴会很慢,如下脚本可一键合并所有的exceldefauto_merge():try:print('...

批量打开一个文件夹下面所有的excel表格

如果现在有一个文件夹,名称叫做“练习表格”,路径名是'C:\Users\123\Desktop\练习表格',现在的要求是打开这个文件下面所有的excel表格,后缀名字为“xlsx”,我...

500行代码,教你用python写个微信飞机大战

这几天在重温微信小游戏的飞机大战,玩着玩着就在思考人生了,这飞机大战怎么就可以做的那么好,操作简单,简单上手。帮助蹲厕族、YP族、饭圈女孩在无聊之余可以有一样东西让他们振作起来!让他们的左手/右手...

python 日志写入_python日志文件写入

1.第一步,新建日志文件路径,如下图:2.日志模块封装,代码如下:importlogging,oslogs_path=os.path.join(os.path.dirname(__file...

Python os.path模块使用指南:轻松处理文件路径

前言在Python编程中,文件和目录的操作是非常重要的一部分。为了方便用户进行文件和目录的操作,Python标准库提供了os模块。其中,os.path子模块提供了一些处理文件路径的函数和方法。本文主要...

Python中获取当前路径之pathilb和os的区别

20230114星期六:1,直接在py脚本中,执行,没有区别;2,打包成exe文件以后,在本机执行,有区别,这时,不能使用os.path.dirname(__file__),只能使用pathlib.P...

Python(办公自动化编程系列)学习笔记1

1、获得当前程序工作目录importos#os.getcwd()函数可以取得当前工作路径的字符串print(os.getcwd())运行结果2、获得程序文件夹相对路径#相对路径都用/表示#../...

文件路径名Pathnames的操作_路径和文件名是什么意思

1.现象问题使用路径名来获取文件名,目录名,绝对路径等等2.原因分析无3.问题解决使用os.path模块中的函数来操作路径名importos.path#查看标准化的绝对路径print...

关于《Python入门:os常用函数》中复制文件(夹)函数从简到繁

基本考虑练习os模块及file读写操作:将给定的源路径的文件(夹)复制到目标路径简单实现#文件到文件的复制path_src='E:\src.txt'path_tar='D...

取消回复欢迎 发表评论: