Spring Cloud Gateway作为OAuth2 Client

1. 引言

Spring Cloud Gateway(后文简称SCG)作为Spring生态新一代的应用网关,其作为整个应用集群的守门人,其除了可以负责路由转发,还可以将本来是属于各个服务的鉴权、限流、熔断等工作统一前置到应用网关统一进行配置管理,从而也减轻了后端接入服务的工作量,使后端服务更专注于核心业务逻辑的开发。同样SCG应用网关也可以将接入OAuth2的工作统一前置到网关中,SCG在OAuth2协议栈中:

  • 既可以充当Resource Server的角色
  • 也可以充当Client的角色。

如果接入OAuth2协议的Client端,如SPA(浏览器端)、Native App(移动app、桌面应用)具有独立完成OAuth2认证(如授权码模式)的能力(语言框架支持、开发人员可以配合修改代码),还是首选SCG仅作为Resource Server,即:

  • SCG仅对access_token进行认证,认证通过才会转发请求到后端服务
  • 后端服务无需关心OAuth2
  • SCG无状态(无需session维护用户登录态、用户信息等)
  • 由Client端自行负责OAuth2授权流程
    • 跳转OAuth2 authorization_endpoint(即跳转到Auth Server登录页)
    • 携带授权码code调用OAuth2 token_endpoint获取access_token、id_token、refresh_token等
    • 维护用户登录态、token及用户信息
    • 携带bearer access_token调用OAuth2 userinfo_endpiont获取用户信息
    • 携带bearer access_token调用SCG(由SCG代理后端服务)

以上SCG作为Resource Server是比较理想的状态(职责划分清晰、SCG无状态),但需要Client端承担一定接入OAuth2的工作量,所以实际向各部门推行此套架构的时候,由于Client端接入OAuth2的门槛最终还是给落地带来了一些阻力,所以为了减轻Client端的接入复杂程度,也就需要SCG承担更多的工作,因此也就引出了本文的核心:SCG作为OAuth2 Client,即:

  • 让SCG来承担与OAuth2授权交互的工作
  • SPA、Web Ajax应用以更简单的方式来接入认证(隔离OAuth2的接入复杂性)
  • SCG作为OAuth2 Client仅适用于浏览器应用(支持cookie)

2. SCG作为OAuth2 Client的整体架构

SCG作为OAuth2 Client的整体架构如下图:


本文讲解的OAuth2接入皆是基于Spring Security OAuth2相关生态,
而Spring Security OAuth2也分为:

  • Servlet Applications - 传统Spring Mvc开发(基于Tomcat、Undertow等容器)
  • Reactive Applications - 基于响应式编程(Web Flux)

由于SCG建立在WebFlux上,所以相关集成说明参见:
https://docs.spring.io/spring-security/reference/reactive/oauth2/index.html

在这里插入图片描述
如上架构设计,即SCG作为OAuth2 Client的首要前提:
仅支持浏览器端应用(支持Cookie Storage、支持302重定向)
如SPA(VUE)、Web Template/Ajax应用等运行在浏览器中的应用,而像Native App(移动app、桌面应用)等无法直接使用Cookie Storage的应用形态,还是首选推荐SCG作为Resource Server的架构,也就是说SCG作为Resource Server的适用性更广(SPA、Native App、Web应用),而SCG作为OAuth2 Client仅适用于浏览器端应用(SPA、Web应用)。

在上述架构中,可以将应用分为3类:

  • 第1类:前端应用 - 运行在浏览器端,向SCG发送请求

    • SPA - 独立运行的SPA应用(如Vue),可与SCG部署在不同域名下
      • 通过Ajax请求SCG后端服务
      • 与SCG跨域
    • Web Template/Ajax - 通过请求后端Web应用渲染Template页面(如Thymeleaf、JSP等)
      • 请求html页面
      • html页面中亦存在Ajax请求,即Ajax请求SCG后端服务
      • html页面和页面中的Ajax请求可隶属于同一Web应用,亦可跨Web应用
      • 通过SCG请求,即与SCG同域名
  • 第2类:后端应用 - 由SCG代理的后端应用

    • Resource Server - 后端API服务,不包含页面
      • 可接入OAuth2 Resource Server,对请求中的bearer access_token(由SCG透传到后端服务)进行认证
    • Web Template/Ajax - 传统web应用,同时提供html页面(如Thymeleaf、JSP等)和Api服务(支持Ajax调用)
  • 第3类:应用网关SCG Client - 负责接入OAuth2授权、维护用户Session及Cookie、透传access_token到后端服务

    • 若浏览器向SCG发起未认证的请求
      • html页面请求(text/html) - 302重定向到SCG Client授权端点
      • Ajax请求(xhr - application/json) - 返回Http 401 Unauthorized
    • 代理OAuth2授权 - /oauth2/authorization/{clientRegId} - 触发SCG Client的OAuth2登录流程
    • 处理OAuth2授权回调 - /login/oauth2/code/{clientRegId}?code=…state=…
    • 获取token、刷新token、透传token到后端服务
    • 维护用户Web Session

前端应用SCG Client间通过Session Cookie来保持用户状态,即由SCG Client完成OAuth2授权流程后,首先将授权信息(access_token、refresh_token、id_token、userInfo)写入到SCG端Session存储,然后再向浏览器端写Session Cookie,之后前端应用(同域、跨域)向SCG发送请求时,会携带SCG域名下的Session Cookie,SCG对Session Cookie认证通过后,可以将access_token透传到后端应用


2.1 SPA作为前端应用接入SCG Client

关于SPA请求SCG Client的完整认证过程参见如下顺序图: 在这里插入图片描述
如上图,SPA接入SCG Client,仅需统一处理Ajax调用返回的Http status 401 Unauthorized,
在收到401后,可统一重定向到SCG Client的自身的OAuth2 Authorization Endpoint:
https://scg-client/oauth2/authorization/{clientRegId}?redirect_uri=https://spa
同时可附加redirect_uri参数,此参数用于设置SPA自身的地址,
SCG Client会在完成OAuth2授权流程后再重定向回此参数指定的uri地址,即重定向回SPA,
此redirect_uri为扩展参数,后文有讲解,并非Spring Security OAuth2 Client原生支持的。

如果后端Api服务不想被任意访问,则SCG可为后端route配置TokenRelay过滤器,即将bearer access_token透传到后端的API服务,
而后端Api服务可以接入Spring Security OAuth2 Resource Server模块来完成对access_token的校验。
如果后端Api服务在部署在内网,不可被公开访问,亦可不开启TokenRelay过滤器,因为SCG Client已经完成过OAuth2登录,即已经认证过用户,所以后端Api服务可无需再对用户进行认证,若有获取用户信息的需要,可参见下面讲解中提到的自定义UserInfoRelay过滤器,将SCG Web Session的用户信息透传到后端Api服务即可。


2.2 SCG Client代理Web Template/Ajax应用

Web Template/Ajax同时包含前端Html页面和后端Api服务,
关于SCG Client代理Web Template/Ajax服务的完整认证过程参见如下顺序图:
在这里插入图片描述
如上图,Web Template/Ajax接入SCG Client,
对于Html页面请求,SCG Client通过SaveRequest、302重定向机制自动完成OAuth2授权流程,
而对于Html页面中的发送后端服务的Ajax请求,仅需统一处理Ajax调用返回的Http status 401 Unauthorized,
在收到401后,可统一重定向到任一Html页面请求(如Homepage),请求Html页面即可由SCG Client自动完成OAuth2授权流程,

若后端服务有获取用户信息的需求,可自定义UserInfoRelay过滤器(实现逻辑参考TokenReplay),
SCG仅需将Web Session中的SPRING_SECURITY_CONTEXT用户信息透传到到后端服务,
而后端服务可根据需要读取x-user-info请求头获取用户信息(无需接入OAuth2 ResourceServer)。


3. SCG集成OAuth2 Client遇到的问题

3.1 分布式session

由于SCG OAuth2 Client与浏览器端前端应用通过Session Cookie保存用户会话及登录态,所以为了保证SCG Client支持水平扩展,所以SCG需要使用分布式Session,如借助Redis存储统一管理Session,而不使用内存Session存储,避免前端请求路由到不同SCG部署实例后无法通过Cookie找到对应的内存Session。
在Spring生态中可以集成使用Spring Session,而Spring Session又分为HttpSession和WebSession等,而SCG(基于WebFlux)则需集成WebSession。

在这里插入图片描述
Spring Session支持的后端存储如下图:
在这里插入图片描述
实际集成时使用的Redis数据存储,具体集成Spring Session Redis Reactive配置application-session.yml如下:

spring:
  # Redis配置
  redis:
    host: localhost
    port: 6379
    database: 0
    #password:
    client-type: lettuce
    lettuce.pool:
      enabled: true
      max-active: 8
      max-idle: 8
      min-idle: 0
      max-wait: -1ms
      #time-between-eviction-runs:
  # Spring Session配置
  session:
    # session超时时间(默认30分钟,即1800s)
    timeout: 600s
    # 启动SpringSession Redis
    store-type: redis
    # SpringSession - Redis相关配置
    redis:
      # 清理失效session的cron表达式(默认每分钟)
      cleanup-cron: 0 * * * * *
      # session存储namespace(key前缀)
      # 默认spring:session
      namespace: scg:client
      # 保存模式,即如何保存Session属性(默认on_set_attribute)
      # on_set_attribute: 仅对调用过Session.setAttribute(String, Object)的属性进行保存
      # on_get_attribute: 仅对调用过Session.setAttribute(String, Object)和Session.getAttribute(String)的属性进行保存
      # always: 全量保存Session中的attributes
      save-mode: on_set_attribute
      # 刷新模式,即何时保存Session(默认on_save)
      # on_save: 仅调用SessionRepository.save(Session)时保存Session,对应提交Response时
      # immediate: 立即保存Session,对应SessionRepository#createSession()或者Session.setAttribute(String. Object)
      flush-mode: on_save
      # 配置活动(默认启用Keyspace events)
      configure-action: notify_keyspace_events
server:
  # webflux session cookie设置
  reactive:
    session:
      cookie:
        # 设置session Cookie名称
        name: SCG_CLIENT_SESSION_ID
        # http-only(禁止JS读取cookie)
        http-only: true
        # cookie过期时长(单位:秒)
        # 设置同Spring Session timeout
        # 默认不设置 空或者<0,即等同于session时效,即关闭浏览器时自动失效
        #max-age: ${spring.session.timeout}
        # =============== 支持Cookie Https且支持CORS ==================
        # cookie secure使用https
        secure: true
        # cookie sameSite设置
        same-site: none

实际开发时,除了上面提到的SCG Client需要支持分布式Session,而AuthServer(基于Spring Authorization Server实现 )也需要支持分布式Session,而AuthServevr基于Servlet容器实现,则需要集成HttpSession,基于HttpSession的配置文件如下:

# 之前的Spring.session配置与上面的配置一样,故省略
# 需要注意的是Cookie设置的前缀是不同的,
# WebSession Cookie配置前缀:server.reactive.session.cookie
# HttpSession Cookie配置前缀:server.servlet.session.cookie
server:
  servlet:
    # 设置session cookie相关
    session:
      cookie:
        # 设置session Cookie名称
        name: AUTH_SERVER_SESSION_ID
        # http-only(禁止JS读取cookie)
        http-only: true
        # cookie过期时长(单位:秒)
        # 设置同Spring Session timeout
        # max-age: ${spring.session.timeout}
        # 默认不设置 空或者<0,即等同于session时效,即关闭浏览器时自动失效

3.2 refresh_token过期导致SCG返回Http Status 500

当前SCG Client检测到(SCG接收到请求时通过TokenRelayGatewayFilterFactory检测)当前用户的access_token还剩1分钟(默认值,可通过设置修改)就过期时,会触发SCG Client端执行Refresh Token授权流程,而此时若SCG Client端存储的refresh_token已经过期时,会导致AuthServer端返回Http status 400 invalid_grant,进而导致SCG返回Http status 500,具体代码实现参见RefreshTokenReactiveOAuth2AuthorizedClientProvider转换OAuth2AuthorizationException为ClientAuthorizationException导致返回
500,此处将ClientAuthorizationException转换为CredentialsExpiredException extends AuthenticationException,可以触发登录(避免返回500),具体SCG Client登录入口实现可参见后续讲解。
在这里插入图片描述

注:
具体的解决思路参见:https://github.com/spring-projects/spring-security/issues/11015
在这里插入图片描述
而GitHub上给出的是将ClientAuthorizationException转换为ClientAuthorizationRequiredException,
会直接302重定向到OAuth2 authorization_endpoint,而我在实际扩展时需要根据请求类型(Html、XHR)决定是重定向、还是返回401,所以最终转换为了CredentialsExpiredException extends AuthenticationException,触发进入SCG Client登录入口,而不是直接重定向到OAuth2 authorization_endpoint。同时由SCG域名跳转到AuthServer域名下authorization_endpoint还有跨域问题。

3.3 设置SCG Client登录入口(Ajax请求401,OPTIONS请求200,其他默认OAuth2 302 Redirect登录)

实际测试时发现Spring Security Reactive的登录入口不是很清晰,所以最后重写了登录入口规则,
即若发现用户未登录,则:

  • Ajax请求:返回Http Status 401
  • CORS Options Preflight请求:返回Http Status 200
  • 其他请求(text/html):Http Status 302 重定向到SCG Client登录端点/oauth2/authorization/{clientRegId}

具体代码配置如下:
在这里插入图片描述

/**
 * 自定义登录端点 - Ajax请求401,OPTIONS请求200,其他默认OAuth2 302 Redirect登录
 */
private ServerAuthenticationEntryPoint buildAjax401AndHtml302AuthEntryPoint() {
    //请求头accept为application/json且忽略*/*
    MediaTypeServerWebExchangeMatcher applicationJsonMatcher = new MediaTypeServerWebExchangeMatcher(MediaType.APPLICATION_JSON);
    applicationJsonMatcher.setIgnoredMediaTypes(Stream.of(MediaType.ALL).collect(Collectors.toSet()));
    List<DelegatingServerAuthenticationEntryPoint.DelegateEntry> delegateEntryList = Arrays.asList(
            //请求头accept为application/json -> 返回401
            new DelegatingServerAuthenticationEntryPoint.DelegateEntry(
                    applicationJsonMatcher,
                    new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)),
            //请求头X-Requested-With为XMLHttpRequest -> 返回401
            new DelegatingServerAuthenticationEntryPoint.DelegateEntry(new ServerWebExchangeMatcher() {
                @Override
                public Mono<MatchResult> matches(ServerWebExchange exchange) {
                    String xRequestedWith = exchange.getRequest().getHeaders().getFirst("X-Requested-With");
                    Boolean match = StringUtils.hasText(xRequestedWith) && xRequestedWith.equals("XMLHttpRequest");
                    return match ? MatchResult.match() : MatchResult.notMatch();
                }
            }, new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)),
            //跨域OPTIONS请求返回200(解决浏览器报错)
            new DelegatingServerAuthenticationEntryPoint.DelegateEntry(new ServerWebExchangeMatcher() {
                @Override
                public Mono<MatchResult> matches(ServerWebExchange exchange) {
                    HttpMethod method = exchange.getRequest().getMethod();
                    Boolean match = HttpMethod.OPTIONS.equals(method);
                    return match ? MatchResult.match() : MatchResult.notMatch();
                }
            }, new HttpStatusServerEntryPoint(HttpStatus.OK))
    );

    DelegatingServerAuthenticationEntryPoint nonAjaxLoginEntryPoint = new DelegatingServerAuthenticationEntryPoint(delegateEntryList);
    //默认登录入口即为OAuth2重定向登录端点
    nonAjaxLoginEntryPoint.setDefaultEntryPoint(new RedirectServerAuthenticationEntryPoint(this.oauth2LoginEndpoint));
    return nonAjaxLoginEntryPoint;
}

3.4 扩展支持redirect_uri参数

为了支持SPA登录跳转(可参见前文SPA作为前端应用接入SCG Client的顺序图),
在这里插入图片描述
即SPA请求SCG OAuth2 Client登录端点/oauth2/authorization/{clientRegId},同时携带redirec_uri参数,SCG会缓存此redirect_uri,在SCG Client认证完成后再由SCG重定向回redirect_url所指向的SPA。设计是如此,但是Spring Security OAuth2 Client是不支持此参数的,所以就需要我们自己扩展实现。

找到如下切入点,即扩展实现SCG OAuth2 Client登录端点/oauth2/authorization/{clientRegId}的解析器:
在这里插入图片描述

具体实现就是扩展原DefaultServerOAuth2AuthorizationRequestResolver实现,提取redirect_uri参数,并模仿WebSessionServerRequestCache保存此redirect_uri到Session中,后续认证完成后Security框架就会自动重定向到此Session中的redirect_uri。

import com.luo.demo.scg.client.config.Oauth2ClientSecurityConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.server.DefaultServerOAuth2AuthorizationRequestResolver;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.web.server.savedrequest.WebSessionServerRequestCache;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Optional;

/**
 * OAuth2 Client Authorization Endpoint /oauth2/authoriztion/{clientRegId} <br/>
 * 请求解析器扩展实现 - 支持提取query参数redirect_uri,用作后续OAuth2认证完成后SCG重定向到该指定redirect_uri。<br/>
 * 适用场景:SPA -> SCG -> SCG返回401 -> SPA重定向到/oauth2/authoriztion/{clientRegId}?redirect_uri=http://spa -> SCG完成OAuth2认证后再重定向回http://spa
 *
 * @author luohq
 * @date 2022-06-13
 * @see DefaultServerOAuth2AuthorizationRequestResolver
 * @see WebSessionServerRequestCache
 * @see Oauth2ClientSecurityConfig
 */
public class SaveRequestServerOAuth2AuthorizationRequestResolver extends DefaultServerOAuth2AuthorizationRequestResolver {

    private static final Log logger = LogFactory.getLog(SaveRequestServerOAuth2AuthorizationRequestResolver.class);

    /**
     * redirect uri参数名称
     */
    private static final String PARAM_REDIRECT_URI = "redirect_uri";

    /**
     * WebSession对应的saveRequest属性名
     * 完全沿用(兼容)WebSessionServerRequestCache定义
     */
    private static final String DEFAULT_SAVED_REQUEST_ATTR = "SPRING_SECURITY_SAVED_REQUEST";
    private String sessionAttrName = DEFAULT_SAVED_REQUEST_ATTR;


    /**
     * Creates a new instance
     *
     * @param clientRegistrationRepository the repository to resolve the
     *                                     {@link ClientRegistration}
     */
    public SaveRequestServerOAuth2AuthorizationRequestResolver(
            ReactiveClientRegistrationRepository clientRegistrationRepository) {
        super(clientRegistrationRepository);
    }

    @Override
    public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange) {
        return super.resolve(exchange)
                .doOnNext(oAuth2AuthorizationRequest -> {
                    //获取query参数redirect_uri
                    Optional.ofNullable(exchange.getRequest())
                            .map(ServerHttpRequest::getQueryParams)
                            .map(queryParams -> queryParams.get(PARAM_REDIRECT_URI))
                            .filter(redirectUris -> !CollectionUtils.isEmpty(redirectUris))
                            .map(redirectUris -> redirectUris.get(0))
                            .ifPresent(redirectUri -> {
                                //若redirect_uri非空,则覆盖Session中的SPRING_SECURITY_SAVED_REQUEST为redirect_uri
                                //即后续认证成功后可重定向回SPA指定页面
                                exchange.getSession().subscribe(webSession -> {
                                    webSession.getAttributes().put(this.sessionAttrName, redirectUri);
                                    logger.debug(LogMessage.format("SCG OAuth2 authorization endpoint queryParam redirect_uri added to WebSession: '%s'", redirectUri));
                                });
                            });
                });
    }

}

3.5 OIDC登出 - 刷新token后同步更新SecurityContext中id_token

SCG Client在集成OidcClientInitiatedServerLogoutSuccessHandler实现OIDC登出时,需要提取SecurityContext中OIDC用户信息中的id_token,

GET end_session_point?id_token_hint={id_token_issued_to_client}&post_logout_redirect_uri={post_logout_redirect_uri}

实际测试发现若执行过Refresh Token流程,虽然SCG Client端存储(OAuth2AuthorizedClient)的access_token和refresh_token都已被动态更新,但是SecurityContext中OIDC用户信息中的id_token还是最初始登录时获取的值,在执行Refresh Token后没有被同步更新,进而导致执行OIDC登出时携带的id_token不是最新的,导致AuthServer返回异常(AuthServer扩展实现返回Http Status 400),所以为了解决这个问题就需要在SCG Client刷新Token后同步更新SecurityContext中OIDC用户信息中的id_token。

SCG Client刷新Token的具体调用链如下:

  • TokenRelayGatewayFilterFactory.apply.authorizedClient
    • ReactiveOAuth2AuthorizedClientManager.authorize(OAuth2AuthorizeRequest)
      • DefaultReactiveOAuth2AuthorizedClientManager.authorize(OAuth2AuthorizeRequest)
        • authorize(OAuth2AuthorizationContext, Authentication, ServerWebExchange)
          • ReactiveOAuth2AuthorizedClientProvider.authorize(OAuth2AuthorizationContext)
            • RefreshTokenReactiveOAuth2AuthorizedClientProvider.authorize(OAuth2AuthorizationContext)

最终定位到RefreshTokenReactiveOAuth2AuthorizedClientProvider,扩展实现如下:
在这里插入图片描述
在这里插入图片描述

3.6 跨域Cookie传输

Web Template/Ajax应用是通过SCG代理,所以请求Web Template/Ajax应用(Html页面、Ajax请求)也是直接请求SCG,然后由SCG路由到对应的Web Template/Ajax应用,即Web Template/Ajax应用是和SCG享有共同的域名的,如:

请求html页面:http://scg-client/webAjax/page
Html页面发送Ajax请求:http://scg-client/webAjax/svc

所以Web Template/Ajax应用和SCG不存在跨域的问题。


SPA可以部署到Nginx中,然后由Nginx路由到SCG Client,如:

请求SPA:http://nginx/spa
SPA向SCG网关发送Ajax请求:http://nginx/scg/resource1

此时SPA和SCG也不存在跨域问题。


而SPA部署在不同域名下(与SCG域名不同),又由于前端应用SPA和SCG间通过Session Cookie保持用户会话及登录态,此时就需要考虑跨域Session Cookie传输的问题了。如SCG Client认证完成后会向浏览器写SCG域名下(Domain=scg-client)的Session Cookie:

Set-Cookie: SCG_CLIENT_SESSION_ID=5f59d21a-31b0-4ab7-b150-59c65a17d5e6; Domain=scg-client,Path=/; HttpOnly;

而SPA部署在不同于SCG的域名下:

http://spa

此时由SPA向SCG发送Ajax请求,即存在跨域及跨域Session Cookie传输的问题,即SPA向SCG发送Ajax请求时默认是无法携带SCG域名下下的Cookie的,导致SCG检测不到Cookie而请求认证失败。若想实现跨域(SPA携带SCG Cookie)Session Cookie的传输,最终解决方案如下:

1)SCG Session Cookie支持Https及跨域传输:

Set-Cookie: SCG_CLIENT_SESSION_ID=5f59d21a-31b0-4ab7-b150-59c65a17d5e6; Path=/; Secure; HttpOnly; SameSite=None

注: 如此也即要求SPA和SCG均使用HTTPS协议

2)SCG(服务端)支持SPA域名及Cookie跨域:

注:setAllowCredentials为true时,allowedOrigin不能为*,即需明确设置allowOrigin对应域名

在这里插入图片描述

3)SPA(客户端)Ajax设置withCredentials=true(即支持跨域Cookie传输):
在这里插入图片描述

4. 示例代码

示例代码参见:https://gitee.com/luoex/oauth2-auth-server-oidc/tree/main/scg-client-prod-sample
在这里插入图片描述


参考:

Spring Session
https://spring.io/projects/spring-session
https://docs.spring.io/spring-boot/docs/current/reference/html/web.html#web.spring-session

SCG & Spring Security OAuth2
https://github.com/spring-projects/spring-security/issues/11015

CORS Cookie
https://geekflare.com/enable-cors-httponly-cookie-secure-token/

Reactor
https://stackoverflow.com/questions/51315378/reactivesecuritycontextholder-getcontext-is-empty-but-authenticationprincipal
https://www.tabnine.com/code/java/classes/org.springframework.security.core.context.ReactiveSecurityContextHolder
https://www.tabnine.com/code/java/methods/reactor.util.context.Context/get

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Cloud Gateway是一个基于Spring Framework 5和Spring Boot 2的微服务网关,它可以帮助开发者快速构建和管理微服务的API网关。OAuth2是一种开放标准的授权协议,可以用于保护API资源,并控制哪些应用程序可以访问这些资源。 在Spring Cloud Gateway中,我们可以很方便地集成OAuth2授权机制。首先,我们需要配置认证服务器的相关信息,包括认证服务器的URL、客户端ID和客户端密钥等。然后,我们可以使用Spring SecurityOAuth2 Client库来配置Gateway作为客户端向认证服务器进行认证和授权。 具体来说,我们需要在Gateway的配置文件中添加以下配置: ``` spring: security: oauth2: client: registration: oauth-provider: client-id: <Client ID> client-secret: <Client Secret> scope: <Scope> provider: <OAuth2 Provider> redirect-uri: <Redirect URI> provider: oauth-provider: authorization-uri: <Authorization URI> token-uri: <Token URI> user-info-uri: <User Info URI> jwk-set-uri: <JWK Set URI> ``` 配置中,`Client ID`和`Client Secret`是我们在认证服务器中注册的客户端ID和密钥。`Scope`表示我们需要获取的访问权限范围。`OAuth2 Provider`表示我们配置的OAuth2认证服务器的名称。`Redirect URI`是认证成功后的回调地址。 `Authorization URI`、`Token URI`、`User Info URI`和`JWK Set URI`分别表示认证服务器的授权、令牌、用户信息和JWK集合的URI。 配置完成后,Gateway就可以通过向认证服务器发送认证请求,获取访问令牌,并将令牌添加到转发请求的请求头中,从而实现对受保护资源的访问。 除了通过配置文件进行配置,我们还可以通过编程方式进行定制,例如自定义认证过滤器、添加额外的认证逻辑等。 综上所述,Spring Cloud GatewayOAuth2的整合,可以有效保护API资源,并对访问资源的客户端进行认证和授权,提高了微服务架构的安全性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗小爬EX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值