Spring Cloud OAuth 微服务内部Token传递的源码实现解析

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 背景分析1.客户端携带认证中心发放的token,请求资源服务器A(Spring Security OAuth 发放Token 源码解析)2.客户端携带令牌直接访问资源服务器,资源服务器通过对token 的校验 ([Spring Cloud OAuth2 资源服务器CheckToken 源码解析](https://my.

背景分析

  • 1.客户端携带认证中心发放的token,请求资源服务器A(Spring Security OAuth 发放Token 源码解析
  • 2.客户端携带令牌直接访问资源服务器,资源服务器通过对token 的校验 ([Spring Cloud OAuth2 资源服务器CheckToken 源码解析
    ](https://my.oschina.net/giegie/blog/3005999)) 判断用户的合法性,并保存到上下文中
  • 3.A服务接口接收到请求,需要通过Feign或者其他RPC框架调用B服务来组装返回数据

本文主要来探讨第三部 A --> B ,token 自定维护的源码实现

如何实现token 传递

配置OAuth2FeignRequestInterceptor 即可

  • 此类是Feign 的拦截器实现

@Bean
@ConditionalOnProperty("security.oauth2.client.client-id")
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext,
                                                        OAuth2ProtectedResourceDetails resource,) {
    return new OAuth2FeignRequestInterceptor(oAuth2ClientContext, resource);
}

源码解析

  • 获取上下文中的token ,组装到请求头
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
    // 给请求增加 token
    @Override
    public void apply(RequestTemplate template) {
        template.header(header, extract(tokenType));
    }
    
    protected String extract(String tokenType) {
        OAuth2AccessToken accessToken = getToken();
        return String.format("%s %s", tokenType, accessToken.getValue());
    }

    // 从spring security 上下文中获取token
    public OAuth2AccessToken getToken() {

        OAuth2AccessToken accessToken = oAuth2ClientContext.getAccessToken();
        if (accessToken == null || accessToken.isExpired()) {
            try {
                accessToken = acquireAccessToken();
            }
        }
        return accessToken;
    }

}
  • 再来看AccessTokenContextRelay, 上下文token 中转器.非常简单从上下文获取认证信息得到把 token 放到上下文
public class AccessTokenContextRelay {

    private OAuth2ClientContext context;

    public AccessTokenContextRelay(OAuth2ClientContext context) {
        this.context = context;
    }
    
    public boolean copyToken() {
        if (context.getAccessToken() == null) {
            Authentication authentication = SecurityContextHolder.getContext()
                    .getAuthentication();
            if (authentication != null) {
                Object details = authentication.getDetails();
                if (details instanceof OAuth2AuthenticationDetails) {
                    OAuth2AuthenticationDetails holder = (OAuth2AuthenticationDetails) details;
                    String token = holder.getTokenValue();
                    DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(
                            token);
                    String tokenType = holder.getTokenType();
                    if (tokenType != null) {
                        accessToken.setTokenType(tokenType);
                    }
                    context.setAccessToken(accessToken);
                    return true;
                }
            }
        }
        return false;
    }

}
  • 什么时候执行中转,oauth2 资源服务器非常简单暴力,加了个拦截器给转发。

源码非常简单

谈谈spring security oauth 实现的问题

  1. 当请求上线文没有Token,如果调用feign 会直接,这个OAuth2FeignRequestInterceptor 肯定会报错,因为上下文copy 失败
  2. 如果设置线程隔离,这里也会报错。导致安全上下问题传递不到子线程中。
  3. 强制使用拦截器去处理 token 转发到这里上下文,使用的业务场景只有这里,影响性能高

这三个问题,大家在使用的过程中一定会遇到

自定义OAuth2FeignRequestInterceptor

  • 通过外部条件是否执行token中转
public void apply(RequestTemplate template) {
    Collection<String> fromHeader = template.headers().get(SecurityConstants.FROM);
    if (CollUtil.isNotEmpty(fromHeader) && fromHeader.contains(SecurityConstants.FROM_IN)) {
        return;
    }

    accessTokenContextRelay.copyToken();
    if (oAuth2ClientContext != null
        && oAuth2ClientContext.getAccessToken() != null) {
        super.apply(template);
    }
}
  • 手动调用accessTokenContextRelay的copy,当然需要覆盖原生oauth 客户端的配置
目录
相关文章
|
2天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
5天前
|
人工智能 监控 安全
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
14 3
|
7天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
17 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
7天前
|
XML Java 数据格式
从入门到精通:Spring基础注解的全面解析
从入门到精通:Spring基础注解的全面解析
25 2
从入门到精通:Spring基础注解的全面解析
|
7天前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
23 0
切面编程的艺术:Spring动态代理解析与实战
|
7天前
|
Java 关系型数据库 MySQL
高级对象装配:解析Spring创建复杂对象的秘诀
高级对象装配:解析Spring创建复杂对象的秘诀
21 0
高级对象装配:解析Spring创建复杂对象的秘诀
|
17天前
|
负载均衡 网络协议 Java
构建高效可扩展的微服务架构:利用Spring Cloud实现服务发现与负载均衡
本文将探讨如何利用Spring Cloud技术实现微服务架构中的服务发现与负载均衡,通过注册中心来管理服务的注册与发现,并通过负载均衡策略实现请求的分发,从而构建高效可扩展的微服务系统。
|
11天前
|
API 数据库 开发者
构建高效可靠的微服务架构:后端开发的新范式
【4月更文挑战第8天】 随着现代软件开发的复杂性日益增加,传统的单体应用架构面临着可扩展性、维护性和敏捷性的挑战。为了解决这些问题,微服务架构应运而生,并迅速成为后端开发领域的一股清流。本文将深入探讨微服务架构的设计原则、实施策略及其带来的优势与挑战,为后端开发者提供一种全新视角,以实现更加灵活、高效和稳定的系统构建。
18 0
|
25天前
|
负载均衡 测试技术 持续交付
高效后端开发实践:构建可扩展的微服务架构
在当今快速发展的互联网时代,后端开发扮演着至关重要的角色。本文将重点探讨如何构建可扩展的微服务架构,以及在后端开发中提高效率的一些实践方法。通过合理的架构设计和技术选型,我们可以更好地应对日益复杂的业务需求,实现高效可靠的后端系统。
|
25天前
|
监控 持续交付 API
构建高效可扩展的微服务架构
在当今快速迭代和竞争激烈的软件市场中,构建一个高效、可扩展且易于维护的后端系统变得尤为重要。微服务架构作为一种流行的分布式系统设计方式,允许开发者将应用程序划分为一系列小型、自治的服务,每个服务负责执行特定的业务功能。本文将探讨如何利用现代技术栈搭建一个符合这些要求的微服务架构,并讨论其潜在的挑战与解决方案。我们将涵盖服务划分策略、容器化、服务发现、API网关、持续集成/持续部署(CI/CD)以及监控和日志管理等关键主题,以帮助读者构建出既可靠又灵活的后端系统。

推荐镜像

更多