当前位置: 首页 > news >正文

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文档

相关文章:

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

前言 之前虽然单独讲过Security Client和Resource Server的对接&#xff0c;但是都是基于Spring webmvc的&#xff0c;Gateway这种非阻塞式的网关是基于webflux的&#xff0c;对于集成Security相关内容略有不同&#xff0c;且涉及到代理其它微服务&#xff0c;所以会稍微比较麻…...

配置Flink

配置flink_1.17.0 1.Flink集群搭建1.1解压安装包1.2修改集群配置1.3分发安装目录1.4启动集群、访问Web UI 2.Standalone运行模式3.YARN运行模式4.K8S运行模式 1.Flink集群搭建 1.1解压安装包 链接: 下载Flink安装包 解压文件 [gpbhadoop102 software]$ tar -zxvf flink-1.1…...

39、springboot的前端静态资源的WebJar支持(bootstrap、jquery等)及自定义图标和首页

★ WebJar支持 Spring Boot支持加载WebJar包中的静态资源&#xff08;图片、JS、CSS&#xff09;&#xff0c; WebJar包中的静态资源都会映射到/webjars/**路径。——这种方式下&#xff0c;完全不需要将静态资源复制到应用的静态资源目录下。只要添加webjar即可。假如在应用的…...

【图论】缩点的综合应用(一)

一.缩点的概念 缩点&#xff0c;也称为点缩法&#xff08;Vertex Contraction&#xff09;&#xff0c;是图论中的一种操作&#xff0c;通常用于缩小图的规模&#xff0c;同时保持了图的某些性质。这个操作的目标是将图中的一些节点合并为一个超级节点&#xff0c;同时调整相关…...

C++—纯虚函数

一、前言 定义一个函数为虚函数&#xff0c;不代表函数为不被实现的函数。 定义函数为虚函数是为了允许用基类的指针来调用子类的这个函数。 定义一个函数为纯虚函数&#xff0c;才代表函数没有被实现。 定义纯虚函数是为了实现一个接口&#xff0c;起到一个规范的作用&…...

经过卷积神经网络之后的图片的尺寸如何计算

经过卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;处理后&#xff0c;图片的尺寸会发生变化&#xff0c;这是由于卷积层、池化层等操作引起的。计算图片经过卷积神经网络后的尺寸变化通常需要考虑卷积核大小、步幅&#xff08;stride&…...

Java升级JDK17(更高版本同理),修改maven

记住三个网址就行&#xff1a;下面这个是oracle的 Java Platform, Standard Edition 17 ReferenceImplementations https://www.oracle.com/java/technologies/downloads/#jdk17-windows 另外一个 redhat旗下的&#xff1a;这个是开源的&#xff08;推荐这个&#xff01;&am…...

Go测试之.golden 文件

Go测试中的.golden 文件是干什么用的&#xff1f;请举例说明 在Go语言中&#xff0c;.golden文件通常用于测试中的黄金文件&#xff08;golden files&#xff09;。黄金文件是在测试期间记录预期输出结果的文件。测试用例运行时&#xff0c;黄金文件用于比较实际输出与预期输出…...

回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现GA-RF遗传算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介绍程…...

springboot整合rabbitmq死信队列

springboot整合rabbitmq死信队列 什么是死信 说道死信&#xff0c;可能大部分观众大姥爷会有懵逼的想法&#xff0c;什么是死信&#xff1f;死信队列&#xff0c;俗称DLX&#xff0c;翻译过来的名称为Dead Letter Exchange 死信交换机。当消息限定时间内未被消费&#xff0c;…...

高中信息技术教资考试模拟卷(22下)

2022 年下半年全国教师资格考试模考卷一 &#xff08;高中信息技术&#xff09; 一、单项选择题&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09; 1.2006 年 10 月 25 日&#xff0c;深圳警方成功解救出一名被网络骗子孙某…...

Linux中shadow及passwd格式内容解析

/etc/passwd文件包括Linux账号信息&#xff0c;示例如下&#xff1a; root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin 具体格式 用户名&#xff1…...

计算机视觉 – Computer Vision | CV

计算机视觉为什么重要&#xff1f; 人的大脑皮层&#xff0c; 有差不多 70% 都是在处理视觉信息。 是人类获取信息最主要的渠道&#xff0c;没有之一。 在网络世界&#xff0c;照片和视频&#xff08;图像的集合&#xff09;也正在发生爆炸式的增长&#xff01; 下图是网络上…...

2.Redis 通用命令

Redis 中最核心的两个命令&#xff1a; set 作用&#xff1a;设置 key 对应的 value 值并存储进去。若key已包含一个值&#xff0c;则无论其类型如何&#xff0c;都会覆盖该值。在SET操作成功时&#xff0c;将丢弃与密钥相关联的任何先前生存时间。 对于上述这里的 key和val…...

【学习FreeRTOS】第18章——FreeRTOS软件定时器

1.软件定时器的简介 定时器&#xff1a;从指定的时刻开始&#xff0c;经过一个指定时间&#xff0c;然后触发一个超时事件&#xff0c;用户可自定义定时器的周期硬件定时器&#xff1a;芯片本身自带的定时器模块&#xff0c;硬件定时器的精度一般很高&#xff0c;每次在定时时…...

C++--两个数组的dp问题(2)

1.交错字符串 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定三个字符串 s1、s2、s3&#xff0c;请判断 s3 能不能由 s1 和 s2 交织&#xff08;交错&#xff09; 组成。 两个字符串 s 和 t 交织 的定义与过程如下&#xff0c;其中每个字符串都…...

利用人工智能彻底改变库存管理:综合指南

通过本指南了解人工智能如何增强库存管理,为希望简化运营的管理者和企业主提供帮助。 库存管理是任何销售实物产品的企业的重要组成部分。它包括跟踪库存水平,预测未来需求,并确保始终有足够的产品来满足客户需求,但又不会因库存过多而浪费金钱。有效的库存管理可以显着降…...

连接器信号完整性仿真教程 七

本将介绍微带线及差分微带线仿真。做连接器信号完整性仿真时&#xff0c;有时后没法将激励端口直接设置到连接器端子上&#xff0c;这就需画出连接器PCB PAD&#xff0c;将激励端口设置在PAD的端面上&#xff0c;或者用引线连接PAD&#xff0c;将引线引出到适当的位置&#xff…...

Wireshark数据抓包分析之UDP协议

一、实验目的&#xff1a; 通过使用wireshark对UDP数据包的抓取分析UDP协议的内容 二、预备知识&#xff1a; UDP协议的概念&#xff1a;UDP使用底层的互联网协议来传送报文&#xff0c;同IP一样提供不可靠的无连接传输服务。它也不提供报文到达确认、排序及流量控制等功能。 …...

Java小游戏

一、需求 二、思路一 HP当然是怪物的一个属性成员&#xff0c;而武器是角色的一个属性成员&#xff0c;类型可以使字符串&#xff0c;用于描述目前角色所装备的武器。角色类有一个攻击方法&#xff0c;以被攻击怪物为参数&#xff0c;当实施一次攻击时&#xff0c;攻击方法被调…...

服务器Linux系统配置mysql数据库主从自动备份

服务器Linux系统配置mysql数据库主从自动备份 当数据内容越来越多的时候&#xff0c;数据库也变得越来越大了。如果不小心误删了&#xff0c;或者被黑主机了&#xff0c;那就什么都没有了。所以数据库的数据怎么能让它不丢失做到万无一失变得尤为重要&#xff01; 我是艾西&a…...

Java通过PowerMockito和Mokito进行单元测试

PowerMockito和Mokito的概念 PowerMockito和Mockito都是Java语言中的测试框架&#xff0c;用于进行单元测试和集成测试。它们中的每一个都有不同的功能和应用。 Mockito是一个基于模拟的测试框架。它允许你模拟对象&#xff0c;在测试中隔离被测代码的依赖项。使用Mockito&am…...

数字化技术无限延伸,VR全景点亮智慧生活

随着互联网的发展&#xff0c;我们无时无刻不再享受着互联网给我们带来的便利&#xff0c;数字化生活正在无限延伸&#xff0c;各行各业也开始积极布局智能生活。要说智慧生活哪个方面应用的比较多&#xff0c;那应该就是VR全景了&#xff0c;目前VR全景已经被各个行业广泛应用…...

抖音艺术签名小程序源码/艺术签名设计小程序源码/字节跳动小程序开发

最近很火的抖音艺术签名小程序源码&#xff0c;这是一款艺术签名设计小程序源码&#xff0c;字节跳动小程序开发&#xff0c;之适用于字节系小程序。介意请绕过&#xff01; 下载地址&#xff1a;https://bbs.csdn.net/topics/616145725...

养号自动化,指纹浏览器和RPA机器人解除烦恼

在这个充满科技魔力的时代&#xff0c;社交媒体已经成为人们生活的一部分&#xff0c;而Facebook更是我们分享欢乐、联络亲友的重要平台。然而&#xff0c;随之而来的是一个棘手的问题&#xff1a;如何保持账号的活跃度&#xff0c;而又不被沉重的养号工作压垮&#xff1f;别担…...

ES6中promise的使用

ES6中promise的使用 本文目录 ES6中promise的使用基础介绍箭头函数function函数状态 原型方法Promise.prototype.then()Promise.prototype.catch() 静态方法Promise.all()Promise.race()Promise.any() 链式回调 基础介绍 官网&#xff1a;https://promisesaplus.com/ window.…...

前端如何走通后端接口

0 写在前面 现在基本都是前后端分离的项目了&#xff0c;那么前端小伙伴如何获取后端小伙伴接口呢&#xff1f; 1 条件 同一WiFi下&#xff0c;让后端小伙伴分享出自己的ip地址&#xff1a; 步骤1:winr调出运行界面 步骤2&#xff1a;cmd调出命令行窗口 步骤3&#xff1a;…...

iOS swift5 扫描二维码

文章目录 1.生成二维码图片2.扫描二维码&#xff08;含上下扫描动画&#xff09;2.1 记得在info.plist中添加相机权限描述 1.生成二维码图片 import UIKit import CoreImagefunc generateQRCode(from string: String) -> UIImage? {let data string.data(using: String.En…...

【马拉车算法/动态规划】最长回文字串

最长回文字串 1.问题描述2.中心扩展法&#xff08;O(N^2)&#xff09;3.动态规划4.Manacher(马拉车算法) 1.问题描述 常用有3种算法&#xff1a;中心扩展法、动态规划和Manacher算法 2.中心扩展法&#xff08;O(N^2)&#xff09; 解释&#xff1a; 从中心向外扩展。 分为两种…...

什么是 fail-fast? 什么是fail-safe?

面试回答 在系统设计中&#xff0c;快速失效&#xff08;fail-fast&#xff09;系统一种可以立即报告任何可能表明故障的情况的系统。快速失效系统通常设计用于停止正常操作&#xff0c;而不是试图继续可能存在缺陷的过程。 其实&#xff0c;这是一种理念&#xff0c;说白了就是…...

网站建设需要多少天时间/seo数据监控平台

https://wiki.wireshark.org/CaptureFilters转载于:https://blog.51cto.com/10500561/1768191...

个人网站-个人主页作业/提高销售的10种方法

定义和使用方法 confirm() 方法用于显示一个带有指定消息和 OK 及取消button的对话框。 语法 confirm(message) 參数 描写叙述 message 要在 window 上弹出的对话框中显示的纯文本&#xff08;而非 HTML 文本&#xff09;说明 假设用户点击确定button&#xff0c;则 confirm() …...

视频分销网站建设/网站建设步骤流程详细介绍

一.问题11.需求&#xff1a;最近在用Vue写后台&#xff0c;其中有个需求被广泛使用&#xff1a;点击签收&#xff0c;立即变成 节点办理|办结2.解决办法&#xff1a;思路;在 节点办理|办结 两个button按钮上绑定v-if的三目运算&#xff0c;当点击签收&#xff0c;签收状…...

网站案例/电商平台运营方案

今天笔试的东西&#xff0c;重载&#xff0c;覆盖和隐藏 重载与覆盖成员函数被重载的特征&#xff1a;&#xff08;1&#xff09;相同的范围&#xff08;在同一个类中&#xff09;&#xff1b; // 这个很重要&#xff0c;如在不同类中则是隐藏&#xff08;2&#xff09;函数名字…...

网站建设价格/青岛网络优化哪家专业

搬到了gipsyh.icu...

j2ee大型网站开发框架/刚刚传来最新消息

使用Vue UI创建、管理项目 1.全局安装vue-cli 3.0 npm install -g vue/cli 2.启动vue ui 创建项目&#xff1a; vue ui 转载于:https://www.cnblogs.com/qicao/p/10713288.html...