美文网首页Java高级架构师之路Java 杂谈Spring-Boot
Spring Cloud OAuth 微服务内部Token传递的

Spring Cloud OAuth 微服务内部Token传递的

作者: Java高级架构师之路 | 来源:发表于2019-04-17 16:29 被阅读3次

    背景分析

    1.客户端携带认证中心发放的token,请求资源服务器A(Spring Security OAuth 发放Token 源码解析)

    2.客户端携带令牌直接访问资源服务器,资源服务器通过对token 的校验 (Spring Cloud OAuth2 资源服务器CheckToken 源码解析 ) 判断用户的合法性,并保存到上下文中

    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 实现的问题

    当请求上线文没有Token,如果调用feign 会直接,这个OAuth2FeignRequestInterceptor 肯定会报错,因为上下文copy 失败

    如果设置线程隔离,这里也会报错。导致安全上下问题传递不到子线程中。

    强制使用拦截器去处理 token 转发到这里上下文,使用的业务场景只有这里,影响性能高

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

    自定义OAuth2FeignRequestInterceptor

    通过外部条件是否执行token中转

    public void apply(RequestTemplate template) {

    Collection 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 客户端的配置

    总结

    以上源码参考个人工作经历

    群712477306欢迎一起来讨论交流Spring Cloud并领取相关完整面试资料

    相关文章

      网友评论

        本文标题:Spring Cloud OAuth 微服务内部Token传递的

        本文链接:https://www.haomeiwen.com/subject/osvnwqtx.html