博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Cloud OAuth 实现微服务内部Token传递的源码解析
阅读量:6536 次
发布时间:2019-06-24

本文共 2969 字,大约阅读时间需要 9 分钟。

  hot3.png

背景分析

  • 1.客户端携带认证中心发放的token,请求资源服务器A()

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

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

总结

  • 以上源码参考个人项目

欢迎关注我们获得更多的好玩JavaEE 实践

转载于:https://my.oschina.net/giegie/blog/3037888

你可能感兴趣的文章
腾讯2017暑期实习编程题3
查看>>
整理收藏一份PHP高级工程师的笔试题
查看>>
Intellij IDEA 构建Spring Web项目 — 用户登录功能
查看>>
[AHOI2013]作业
查看>>
git push被忽略的文件 处理
查看>>
C#中用ILMerge将所有引用的DLL打成一个DLL文件
查看>>
PHP生成HTML静态页面
查看>>
服务器启动django
查看>>
Makefile 中:= ?= += =的区别【转】
查看>>
使用makecontext实现用户线程【转】
查看>>
Comet:基于 HTTP 长连接的“服务器推”技术
查看>>
BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
查看>>
四种方法校验数组中是否包含某个指定的字符串
查看>>
29、Java并发性和多线程-非阻塞算法
查看>>
安装OpenResty开发环境
查看>>
第0课 从0开始
查看>>
hadoop无法启动DataNode问题
查看>>
java泛型中<?>和<T>区别
查看>>
这里是指推送通知跟NSNotification有区别:
查看>>
Linux中断(interrupt)子系统之一:中断系统基本原理【转】
查看>>