Spring Authorization Server入门 (十六) Spring Cloud Gateway对接认证服务

前言

        之前虽然单独讲过Security Client和Resource Server的对接,但是都是基于Spring webmvc的,Gateway这种非阻塞式的网关是基于webflux的,对于集成Security相关内容略有不同,且涉及到代理其它微服务,所以会稍微比较麻烦些,今天就带大家来实现Gateway网关对接OAuth2认证服务。

Gateway对接说明

身份问题

        在本次示例中网关既是客户端(OAuth2 Client Server)又是资源服务(OAuth2 Resource Server),Client服务负责认证,Resource负责鉴权,这样如果有在浏览器直接访问网关的需要可以直接在浏览器由框架引导完成OAuth2认证过程。

框架版本与架构说明

架构图

spring cloud 微服务.jpg

Spring Cloud依赖版本

框架版本号
Spring Boot3.1.0
Nacos Server2.2.1
Spring Cloud2022.0.4
Spring Cloud Alibaba2022.0.0.0
Spring Security6.1.0
Spring OAuth2 Client6.1.0
Spring OAuth2 Resource Server6.1.0

读者可以自选版本使用,作为对接方版本问题不大;不确定Spring Cloud Alibaba 在部署时会不会有Spring Boot的版本限制,如果3.1.x无法使用请降级至3.0.10版本,开发时测试都是没问题的。

网关集成认证服务请求流程图说明

Spring Cloud Gateway对接OAuth2认证服务.jpg

  1. 用户请求受限资源
  2. 网关检测没有认证信息,通过RedirectServerAuthenticationEntryPoint处理并发起OAuth2登录授权申请
  3. 授权申请到达认证服务,认证服务检测到未登录重定向至登录页面并展示给用户
  4. 用户登录成功后请求重定向至授权申请接口,通过校验后携带Token重定向至回调地址(redirect_uri),注意:这里回调地址要设置为网关的地址,htttp://{网关ip}:{网关port}/login/oauth2/code/{registrationId},后边的/login/oauth2/code/{registrationId}路径是固定的,这是框架(Security OAuth2 Client)自带的端点
  5. 请求到达网关,由OAuth2LoginAuthenticationWebFilter拦截并调用父类AuthenticationWebFilterfilter方法进行处理
  6. AuthenticationWebFilter调用OidcAuthorizationCodeReactiveAuthenticationManagerOAuth2LoginReactiveAuthenticationManager类处理(由授权申请的scope决定,包含openid就走OidcAuthorizationCodeReactiveAuthenticationManager,否则走另一个)
  7. 在获取AccessToken成功以后调用ReactiveOAuth2UserService获取用户信息
  8. 获取到用户信息后会解析并将认证信息保存至ReactiveSecurityContextHolder
  9. 完成这一系列的认证之后会重定向至最一开始请求的受限资源,这时候就能获取到认证信息了
  10. 如果访问的是被网关代理的服务则会通过令牌中继(TokenRelay)携带token访问

这就是网关通过认证服务获取认证信息的一个流程,基本上只需要添加配置文件即可由框架引导进行OAuth2认证流程。

开始编码

前置条件

  1. 搭建好标准OAuth2认证服务
  2. 搭建nacos服务

项目结构

项目结构

gateway-example # 父模块│  ├─gateway-client-example # 网关│  ├─normal-resource-example # webmvc资源服务│  ├─webflux-resource-example # webflux资源服务│  └─pom.xml # 公共依赖,依赖管理

创建一个空的maven项目

引入Spring Boot、Spring Cloud、Spring Cloud Alibaba,如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.0</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>gateway-example</artifactId><version>0.0.1</version><packaging>pom</packaging><name>gateway-example</name><description>gateway-example</description><modules><module>gateway-client-example</module><module>normal-resource-example</module><module>webflux-resource-example</module></modules><properties><java.version>17</java.version><!-- 修复漏洞 --><snakeyaml.version>2.0</snakeyaml.version><!-- Spring Cloud版本号 --><spring-cloud.version>2022.0.4</spring-cloud.version><!-- Spring Cloud Alibaba版本号 --><spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version></properties><dependencies><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- Spring Boot 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 服务注册与发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- 配置中心 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!-- 资源服务器starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement></project>

里边的modules标签是在新建module时自动添加的

创建网关gateway-client-example模块

创建gateway-client-example模块

Spring Cloud 相关依赖已经在parent模块中引入,所以该模块只需要引入Gateway、Client依赖,pom如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>gateway-example</artifactId><version>0.0.1</version></parent><artifactId>gateway-client-example</artifactId><name>gateway-client-example</name><description>gateway-client-example</description><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>io.projectreactor</groupId><artifactId>reactor-test</artifactId><scope>test</scope></dependency><!-- 负载均衡依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

编写客户端配置

package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;import java.util.Collection;
import java.util.HashSet;
import java.util.Set;/*** 客户端配置** @author vains*/
@Configuration
public class ClientServerConfig {/*** 解析用户权限信息(当在浏览器中直接访问接口,框架自动调用OIDC流程登录时会用到该配置)** @return GrantedAuthoritiesMapper*/@Beanpublic GrantedAuthoritiesMapper userAuthoritiesMapper() {return (authorities) -> {Set<GrantedAuthority> mappedAuthorities = new HashSet<>();authorities.forEach(authority -> {if (authority instanceof OAuth2UserAuthority oAuth2UserAuthority) {// 从认证服务获取的用户信息中提取权限信息Object userAuthorities = oAuth2UserAuthority.getAttributes().get("authorities");if (userAuthorities instanceof Collection<?> collection) {// 转为SimpleGrantedAuthority的实例并插入mappedAuthorities中collection.stream().filter(a -> a instanceof String).map(String::valueOf).map(SimpleGrantedAuthority::new).forEach(mappedAuthorities::add);}}});return mappedAuthorities;};}}

该配置会在获取到用户信息后解析用户的权限信息,详见文档

编写网关资源服务配置

package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;/*** 资源服务器配置** @author vains*/
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class ResourceServerConfig {/*** 配置认证相关的过滤器链** @param http Spring Security的核心配置类* @return 过滤器链*/@Beanpublic SecurityWebFilterChain defaultSecurityFilterChain(ServerHttpSecurity http) {// 禁用csrf与corshttp.csrf(ServerHttpSecurity.CsrfSpec::disable);http.cors(ServerHttpSecurity.CorsSpec::disable);// 开启全局验证http.authorizeExchange((authorize) -> authorize//全部需要认证.anyExchange().authenticated());// 开启OAuth2登录http.oauth2Login(Customizer.withDefaults());// 设置当前服务为资源服务,解析请求头中的tokenhttp.oauth2ResourceServer((resourceServer) -> resourceServer// 使用jwt.jwt(jwt -> jwt// 请求中携带token访问时会触发该解析器适配器.jwtAuthenticationConverter(grantedAuthoritiesExtractor()))/*// xhr请求未携带Token处理.authenticationEntryPoint(this::authenticationEntryPoint)// 权限不足处理.accessDeniedHandler(this::accessDeniedHandler)// Token解析失败处理.authenticationFailureHandler(this::failureHandler)*/);return http.build();}/*** 自定义jwt解析器,设置解析出来的权限信息的前缀与在jwt中的key** @return jwt解析器适配器 ReactiveJwtAuthenticationConverterAdapter*/public Converter<Jwt, Mono<AbstractAuthenticationToken>> grantedAuthoritiesExtractor() {JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();// 设置解析权限信息的前缀,设置为空是去掉前缀grantedAuthoritiesConverter.setAuthorityPrefix("");// 设置权限信息在jwt claims中的keygrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);}}

需要注意的是开启方法级别鉴权的注解变了,webflux的注解和webmvc的注解不一样,并且过滤器链也换成SecurityWebFilterChain了;jwt自定义解析器的方式也不一致,实现方式见上方代码

说明文档如下

EnableReactiveMethodSecurity注解文档

Jwt解析器适配器详见文档

编写application.yml,添加nacos配置

spring:cloud:nacos:serverAddr: 127.0.0.1:8848config:import:- nacos:gateway.yml?refresh=trueapplication:name: gateway

在nacos中创建gateway.yml配置文件

添加客户端与资源服务配置,并添加其它资源服务的代理配置

server:port: 7000
spring:security:oauth2:# 资源服务器配置resourceserver:jwt:# Jwt中claims的iss属性,也就是jwt的签发地址,即认证服务器的根路径# 资源服务器会进一步的配置,通过该地址获取公钥以解析jwtissuer-uri: http://192.168.119.1:8080client:provider:# 认证提供者,自定义名称custom-issuer:# Token签发地址(认证服务地址)issuer-uri: http://192.168.119.1:8080# 获取用户信息的地址,默认的/userinfo端点需要IdToken获取,为避免麻烦自定一个用户信息接口user-info-uri: ${spring.security.oauth2.client.provider.custom-issuer.issuer-uri}/useruser-name-attribute: nameregistration:messaging-client-oidc:# oauth认证提供者配置,和上边配置的认证提供者关联起来provider: custom-issuer# 客户端名称,自定义client-name: gateway# 客户端id,从认证服务申请的客户端idclient-id: messaging-client# 客户端秘钥client-secret: 123456# 客户端认证方式client-authentication-method: client_secret_basic# 获取Token使用的授权流程authorization-grant-type: authorization_code# 回调地址,这里设置为Spring Security Client默认实现使用code换取token的接口,当前服务(gateway网关)的地址redirect-uri: http://127.0.0.1:7000/login/oauth2/code/messaging-client-oidcscope:- message.read- message.write- openid- profilecloud:gateway:default-filters:# 令牌中继- TokenRelay=# 代理路径,代理至服务后会去除第一个路径的内容- StripPrefix=1routes:# 资源服务代理配置- id: resourceuri: lb://resourcepredicates:- Path=/resource/**# 资源服务代理配置- id: webfluxuri: lb://webflux-resourcepredicates:- Path=/webflux/**

注意:配置文件中令牌中继(TokenRelay)的配置就是添加一个filterTokenRelay=; 当网关引入spring-boot-starter-oauth2-client依赖并设置spring.security.oauth2.client.*属性时,会自动创建一个TokenRelayGatewayFilterFactory过滤器,它会从认证信息中获取access token,并放入下游请求的请求头中。 详见Gateway关于TokenRelay的文档

项目结构

网关项目结构

创建webmvc资源服务模块normal-resource-example

在pom.xml中添加web依赖,如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>gateway-example</artifactId><version>0.0.1</version></parent><artifactId>normal-resource-example</artifactId><name>normal-resource-example</name><description>normal-resource-example</description><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

创建资源服务器配置,添加自定义jwt解析器

package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;/*** 资源服务器配置** @author vains*/
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class ResourceServerConfig {/*** 自定义jwt解析器,设置解析出来的权限信息的前缀与在jwt中的key** @return jwt解析器 JwtAuthenticationConverter*/@Beanpublic JwtAuthenticationConverter jwtAuthenticationConverter() {JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();// 设置解析权限信息的前缀,设置为空是去掉前缀grantedAuthoritiesConverter.setAuthorityPrefix("");// 设置权限信息在jwt claims中的keygrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);return jwtAuthenticationConverter;}}

编写application.yml添加nacos配置

spring:cloud:nacos:serverAddr: 127.0.0.1:8848config:import:- nacos:resource.yml?refresh=trueapplication:name: resource

在nacos中创建resource.yml配置文件,添加资源服务配置

server:port: 7100spring:security:oauth2:# 资源服务器配置resourceserver:jwt:# Jwt中claims的iss属性,也就是jwt的签发地址,即认证服务器的根路径# 资源服务器会进一步的配置,通过该地址获取公钥以解析jwtissuer-uri: http://192.168.119.1:8080

注意端口,不能与网关和认证服务重复

模块结构

normal-resource-example结构

创建webflux资源服务模块

pom.xml添加webflux依赖,如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>gateway-example</artifactId><version>0.0.1</version></parent><artifactId>webflux-resource-example</artifactId><name>webflux-resource-example</name><description>webflux-resource-example</description><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build>
</project>

创建资源服务配置并且添加jwt解析器适配器

跟网关的资源服务配置差不多,如下

package com.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;/*** 资源服务器配置** @author vains*/
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class ResourceServerConfig {/*** 配置认证相关的过滤器链** @param http Spring Security的核心配置类* @return 过滤器链*/@Beanpublic SecurityWebFilterChain defaultSecurityFilterChain(ServerHttpSecurity http) {// 禁用csrf与corshttp.csrf(ServerHttpSecurity.CsrfSpec::disable);http.cors(ServerHttpSecurity.CorsSpec::disable);// 开启全局验证http.authorizeExchange((authorize) -> authorize//全部需要认证.anyExchange().authenticated());// 设置当前服务为资源服务,解析请求头中的tokenhttp.oauth2ResourceServer((resourceServer) -> resourceServer// 使用jwt.jwt(jwtSpec -> jwtSpec// 设置jwt解析器适配器.jwtAuthenticationConverter(grantedAuthoritiesExtractor())));return http.build();}/*** 自定义jwt解析器,设置解析出来的权限信息的前缀与在jwt中的key** @return jwt解析器适配器 ReactiveJwtAuthenticationConverterAdapter*/public Converter<Jwt, Mono<AbstractAuthenticationToken>> grantedAuthoritiesExtractor() {JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();// 设置解析权限信息的前缀,设置为空是去掉前缀grantedAuthoritiesConverter.setAuthorityPrefix("");// 设置权限信息在jwt claims中的keygrantedAuthoritiesConverter.setAuthoritiesClaimName("authorities");JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);}}

编写application.yml添加nacos配置

spring:cloud:nacos:serverAddr: 127.0.0.1:8848config:import:- nacos:webflux.yml?refresh=trueapplication:name: webflux-resource

nacos中添加webflux.yml配置文件并添加资源服务配置

server:port: 7200spring:security:oauth2:# 资源服务器配置resourceserver:jwt:# Jwt中claims的iss属性,也就是jwt的签发地址,即认证服务器的根路径# 资源服务器会进一步的配置,通过该地址获取公钥以解析jwtissuer-uri: http://192.168.119.1:8080

与webmvc的资源服务的配置是一样的,注意端口不能与其它服务端口冲突

模块结构

webflux-resource-example模块结构

在三个模块中添加测试类,一式三份

webmvc测试接口

package com.example.controller;import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;/*** 测试接口** @author vains*/
@RestController
public class TestController {@GetMapping("/test01")@PreAuthorize("hasAnyAuthority('message.write')")public String test01() {return "test01";}@GetMapping("/test02")@PreAuthorize("hasAnyAuthority('test02')")public String test02() {return "test02";}@GetMapping("/app")@PreAuthorize("hasAnyAuthority('app')")public String app() {return "app";}}

webflux测试接口

package com.example.controller;import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;/*** 测试接口** @author vains*/
@RestController
public class TestController {@GetMapping("/test01")@PreAuthorize("hasAnyAuthority('message.write')")public Mono<String> test01() {return Mono.just("test01");}@GetMapping("/test02")@PreAuthorize("hasAnyAuthority('test02')")public Mono<String> test02() {return Mono.just("test02");}@GetMapping("/app")@PreAuthorize("hasAnyAuthority('app')")public Mono<String> app() {return Mono.just("app");}}

测试

前置条件

  1. 启动认证服务
  2. 启动nacos
  3. nacos中都有相关配置

启动项目

依次启动三个服务,顺序无所谓

在postman中直接访问网关接口或代理的服务接口

在postman中直接访问网关
被重定向至登录了,携带X-Requested-With请求头访问,代表当前是xhr请求

携带请求头访问
响应401,框架有区分是浏览器请求还是xhr请求,对于浏览器请求会重定向到页面,对于xhr请求默认会响应401状态码,可自己实现异常处理,这里错误信息在请求头中是因为没有重写异常处理,网关资源服务配置代码中有注释。

在浏览器中访问网关接口或代理的服务接口

访问

浏览器打开地址:http://127.0.0.1:7000/resource/app

引导请求至认证服务发起授权申请
请求到达网关后检测到未登录会引导用户进行OAuth2认证流程

登录后提交

登录后提交
登录提交后认证服务重定向授权申请接口,校验通过后会生成code并携带code重定向至回调地址,注意,这里的回调地址是网关的服务地址,由网关中的OAuth2 Client处理,如图

网关根据code换取token
网关会根据code换取token,获取token后根据token获取用户信息,并调用网关客户端配置中自定义的userAuthoritiesMapper解析权限信息。

访问权限不足的接口

权限不足
响应403,并将错误信息放入响应头中

使用token访问网关

过期token

过期token
响应401并在响应头中提示token已过期

错误token

错误token
响应401并在响应头中提示token无法解析

权限不足token

权限不足

响应403并提示权限不足

正常请求

正常请求
响应200并正确响应接口信息

写在最后

本文带大家简单实现了Spring Cloud Gateway对接认证服务,Gateway中添加客户端主要是为了如果代理服务有静态资源(html、css、image)时可以直接发起OAuth2授权流程,在浏览器登录后直接访问,同时也是开启令牌中继的必要依赖;引入Resource Server依赖是当需要对网关的接口鉴权时可以直接使用,如果网关只负责转发应该是可以去掉资源服务相关依赖和配置的,由各个被代理的微服务对自己的接口进行鉴权。这些东西在之前基本都是讲过的内容,所以本文很多地方都是一笔带过的,如果某些地方不清楚可以针对性的翻翻之前的文章,也可以在评论区中提出。
如果有什么问题或者需要补充的请在评论区指出,谢谢。

附录

Gitee仓库地址

Gateway令牌中继文档

OAuth2登录后用户权限解析文档

webflux开启方法鉴权EnableReactiveMethodSecurity注解说明文档

webflux的Jwt解析器适配器说明文档

webflux对接OAuth2 Client文档

webflux对接OAuth2 Resource Server文档

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

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

相关文章

怎么把pdf转换成jpg格式?

怎么把pdf转换成jpg格式&#xff1f;在我们日常的办公过程中&#xff0c;PDF文件是一个经常被使用来传输文件的格式。它能够确保我们的文件内容不会混乱&#xff0c;并以更加完美的方式呈现出来。然而&#xff0c;PDF文件也存在一些缺陷。例如&#xff0c;它无法直接编辑&#…

React+Typescript从请求数据到列表渲染

我们在项目src目录下创建一个目录 叫 pages 在里面创建一个组件叫 list.tsx 这里 我启动了自己的java项目 创建接口 你们就也需要弄几个自己的接口做测试 然后 list.tsx 编写代码如下 import * as React from "react";export default class hello extends React.C…

【seaweedfs】3、f4: Facebook’s Warm BLOB Storage System 分布式对象存储的冷热数据

论文地址 Facebook的照片、视频和其他需要可靠存储和快速访问的二进制大型对象(BLOB)的语料库非常庞大&#xff0c;而且还在继续增长。随着BLOB占用空间的增加&#xff0c;将它们存储在我们传统的存储系统-- Haystack 中变得越来越低效。为了提高我们的存储效率(以Blob的有效复…

基于安卓的考研助手系统app 微信小程序

&#xff0c;设计并开发实用、方便的应用程序具有重要的意义和良好的市场前景。HBuilder技术作为当前最流行的操作平台&#xff0c;自然也存在着大量的应用服务需求。 本课题研究的是基于HBuilder技术平台的安卓的考研助手APP&#xff0c;开发这款安卓的考研助手APP主要是为了…

计算机系统真题

计算机系统真题 考点计算机系统存储体系磁盘调度算法 考点 计算机系统 PC找到指令&#xff0c;存储到IR中 根据ID分析指令的操作&#xff0c;并执行指令,AR访问操作数 A pc存指令的地址 内存按照字节编址&#xff1a; 在统一单位&#xff0c;转换一下&#xff1a; 3x2的平方 …

Unix时间戳

江科大学习记录 Unix时间戳 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64位的整型变量世界上所有时区的秒计数器相同&#xf…

HTML番外篇(五)-移动端适配

一、媒体查询 1.认识媒体查询 媒体查询是一种提供给开发者针对不同设备需求进行定制化开发的一个接口。 你可以根据设备的类型&#xff08;比如屏幕设备、打印机设备&#xff09;或者特定的特性(比如屏幕的宽度)来修改你的页面。 媒体查询的使用方式主要有三种&#xff1a;…

算法笔记:球树

1 KD树的问题 算法笔记&#xff1a;KD树_UQI-LIUWJ的博客-CSDN博客 在kd树中&#xff0c;导致性能下降的最核心因素是因为kd-tree中被分割的子空间是一个个的超方体&#xff0c;而求最近邻时使用的是欧式距离&#xff08;超球&#xff09;。超方体与超球体相交的可能性是极高…

【VsCode】SSH远程连接Linux服务器开发,搭配cpolar内网穿透实现公网访问(1)

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

SpringBootWeb案例 Part3

目录 1. 新增员工 1.1 需求 1.2 接口文档 1.3 思路分析 PostMapping RequestBody //把前端传递的JSON数据填充到实体类中 1.4 功能开发 1.5 功能测试 1.6 前后端联调 2. 文件上传 2.1 文件上传简介 Spring中提供了一个API&#xff1a;MultipartFile&#xff0c;使…

爬虫逆向实战(二十一)-- 某某点集登录与获取数据

登录 一、数据接口分析 主页地址&#xff1a;某某点集 1、抓包 通过抓包可以发现登录接口是phonePwdLogin 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有pwd和sig两个加密参数 请求头是否加密&#xff1f; 无响应是否加密&#x…

144. 二叉树的前序遍历-C++

题目来源&#xff1a;力扣 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[] 代码实现&#xff1a; class Solution { public:vector<int> preorderTraversal(TreeNo…

深入理解linux内核--程序的执行

可执行文件 在第一章中我们把进程定义为“执行上下文”。这就意味着进行特定的计算需要收集必要的信息&#xff0c;包括所访问的页&#xff0c;打开的文件&#xff0c;硬件寄存器的内容等等。 可执行文件是一个普通文件&#xff0c;它描述了如何初始化一个新的执行上下文&…

飞腾FT-2000/4、D2000 log报错指导(1)

在爱好者群中遇见了很多的固件问题,这里总结记录了大家的交流内容和调试心得。主要是飞腾桌面CPU FT-2000/4 D2000相关的,包含uboot和UEFI。希望对大家调试有所帮助。 这个专题会持续更新,凑够一些就发。 1 UEFI启动时报错: ASSERT_EFI_ERROR (Status = Not Found) ASS…

ubuntu20.04 直接安装vpp23.06 测试双 VPP Tunnel Ike2

环境信息&#xff1a;VMware Workstation 17 Pro ubuntu20.04 (清华源) ubuntu 源点进去选&#xff1a;ubuntu-22.04.3-desktop-amd64.iso 如果之前装过VPP&#xff0c;用以下命令确定是否卸载干净&#xff1a; dpkg -l | grep vpp dpkg -l | grep DPDK 卸载&#xff1a; …

【springboot】WebScoket双向通信:

文章目录 一、介绍&#xff1a;二、案例&#xff1a;三、使用&#xff1a;【1】导入WebSocket的maven坐标【2】导入WebSocket服务端组件WebSocketServer&#xff0c;用于和客户端通信【3】导入配置类WebSocketConfiguration&#xff0c;注册WebSocket的服务端组件【4】导入定时…

DevOps系列文章 之 Python基础

Python语法结构 语句块缩进 1.python代码块通过缩进对齐表达代码逻辑而不是使用大括号 2.缩进表达一个语句属于哪个代码块 3.缩进风格 &#xff1a; 建议使用四个空格 如果是Linux系统的话&#xff0c;可以这样做&#xff0c;实现自动缩进 &#xff1a; vim ~/.vimrc set ai…

中国芯,寻找新赛道迫在眉睫

北京华兴万邦管理咨询有限公司 商瑞 陈皓 近期国内半导体行业的热点可以用两个“有点多”来描述&#xff0c;一个是中国芯群体中上市公司股价闪崩的有点多&#xff0c;另一个是行业和企业的活动有点多。前者说明了许多国内芯片设计企业&#xff08;fabless商业模式&#xff09;…

编写Dockerfile制作Web应用系统nginx镜像,生成镜像nginx:v1.1,并推送其到私有仓库。

环境&#xff1a; CentOS 7 Linux 3.10.0-1160.el7.x86_64 具体要求如下&#xff1a; &#xff08;1&#xff09;基于centos基础镜像&#xff1b; &#xff08;2&#xff09;指定作者信息&#xff1b; &#xff08;3&#xff09;安装nginx服务&#xff0c;将提供的dest目录…

计算机安全学习笔记(I):访问控制安全原理

访问控制原理 从广义上来讲&#xff0c;所有的计算机安全都与访问控制有关。 RFC 4949: Internet Security Glossary, Version 2 (rfc-editor.org) RFC 4949 定义的计算机安全&#xff1a;用来实现和保证计算机系统的安全服务的措施&#xff0c;特别是保证访问控制服务的措施…