扩展资源服务器解决oauth2 性能瓶颈
- 用户携带token 请求资源服务器
- 资源服务器拦截器 携带token 去认证服务器 调用tokenstore 对token 合法性校验
- 资源服务器拿到token,默认只会含有用户名信息
- 通过用户名调用userdetailsservice.loadbyusername 查询用户全部信息
详细性能瓶颈分析,请参考上篇文章《扩展jwt解决oauth2 性能瓶颈》
本文是针对传统使用UUID token 的情况进行扩展,提高系统的吞吐率,解决性能瓶颈的问题
默认check-token 解析逻辑
- RemoteTokenServices 入口
@Override public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>(); formData.add(tokenName, accessToken); HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", getAuthorizationHeader(clientId, clientSecret)); // 调用认证服务器的check-token 接口检查token Map<String, Object> map = postForMap(checkTokenEndpointUrl, formData, headers); return tokenConverter.extractAuthentication(map); }
- 解析认证服务器返回的信息
DefaultAccessTokenConverter
public OAuth2Authentication extractAuthentication(Map<String, ?> map) { Map<String, String> parameters = new HashMap<String, String>(); Set<String> scope = extractScope(map); // 主要是 用户的信息的抽取 Authentication user = userTokenConverter.extractAuthentication(map); // 一些oauth2 信息的填充 OAuth2Request request = new OAuth2Request(parameters, clientId, authorities, true, scope, resourceIds, null, null, null); return new OAuth2Authentication(request, user); }
- 组装当前用户信息
DefaultUserAuthenticationConverter
public Authentication extractAuthentication(Map<String, ?> map) { if (map.containsKey(USERNAME)) { Object principal = map.get(USERNAME); Collection<? extends GrantedAuthority> authorities = getAuthorities(map); if (userDetailsService != null) { UserDetails user = userDetailsService.loadUserByUsername((String) map.get(USERNAME)); authorities = user.getAuthorities(); principal = user; } return new UsernamePasswordAuthenticationToken(principal, "N/A", authorities); } return null; }
问题分析
- 认证服务器check-token 返回的全部信息
- 资源服务器在根据返回信息组装用户信息的时候,只是用了username
- 如果设置了 userDetailsService 的实现则去调用 loadUserByUsername 再去查询一次用户信息
造成问题现象
- 如果设置了userDetailsService 即可在spring security 上下文获取用户的全部信息,不设置则只能得到用户名。
- 增加了一次查询逻辑,对性能产生不必要的影响
解决问题
- 扩展UserAuthenticationConverter 的解析过程,把认证服务器返回的信息全部组装到spring security的上下文对象中
/** * @author lengleng * @date 2019-03-07 * <p> * 根据checktoken 的结果转化用户信息 */ public class PigxUserAuthenticationConverter implements UserAuthenticationConverter { private static final String N_A = "N/A"; // map 是check-token 返回的全部信息 @Override public Authentication extractAuthentication(Map<String, ?> map) { if (map.containsKey(USERNAME)) { Collection<? extends GrantedAuthority> authorities = getAuthorities(map); String username = (String) map.get(USERNAME); Integer id = (Integer) map.get(SecurityConstants.DETAILS_USER_ID); Integer deptId = (Integer) map.get(SecurityConstants.DETAILS_DEPT_ID); Integer tenantId = (Integer) map.get(SecurityConstants.DETAILS_TENANT_ID); PigxUser user = new PigxUser(id, deptId, tenantId, username, N_A, true , true, true, true, authorities); return new UsernamePasswordAuthenticationToken(user, N_A, authorities); } return null; } }
- 给remoteTokenServices 注入这个实现
public class PigxResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); UserAuthenticationConverter userTokenConverter = new PigxUserAuthenticationConverter(); accessTokenConverter.setUserTokenConverter(userTokenConverter); remoteTokenServices.setRestTemplate(lbRestTemplate); remoteTokenServices.setAccessTokenConverter(accessTokenConverter); resources. .tokenServices(remoteTokenServices); } }
- 完成扩展,再来看文章开头的流程图就变成了如下
关注我
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
从RocketMQ我们学到了什么之NameServer
微信公众号:IT一刻钟 大型现实非严肃主义现场,一刻钟与你分享优质技术架构与见闻,做一个有剧情的程序员 序 在很久很久以前,人们之间的通信方式就是面对面交谈,你说一句,我听一句,虽然简单可靠,但是弊端也很大。 比如,当你成为一个军队的首领,每个属下一有情况就立刻向你汇报,一个还好,但当你的属下有几十个几百个的时候,他们每天不分时间不看场合,都在叽叽喳喳和你汇报情况,那你可能什么都听不到,而且脑袋都要炸掉了。这个时候,你说停,都给我停下,要汇报情况的,去门口排队,一个一个的来,这个就叫做流量削峰,一群人不要一拥而上,都乖乖给我排队去。 然后你就一个接一个的听,听了整整24个小时,实在困的不行,寻思着这样不行呀,如此下去可能就要天妒英才了,于是你又说,来人,发笔和纸,都把要汇报的消息写在纸上,写完后告诉吕秀才,然后听吕秀才的指示,沿着屋里右面墙根,按照指示的位置叠放整齐,汇报的人就可以退下该做啥做啥去吧,等我休息一下,再来看你们的汇报内容,这就叫做异步处理,你终于可以由自己掌控消息获取的进度了,美滋滋的去睡觉了。 而汇报的人把内容写在纸上,叠放好,就可以退下自己做自己该做的事情,而不是一直...
- 下一篇
我的ImageIO.write ByteArrayOutputStream为什么这么慢?
问题来源: 1.系统生成二维码,需要不同的图片格式来适应客户端要求 2.图片通过接口模式给客户端,最终使用base64来传递 平常思考模式: 1.BufferedImage首先通过工具把数据生成出来。 2.我绝对不会把这个BufferedImage写磁盘,直接放内存ByteArrayOutputstream后转base64岂不是更快? 3.ImageIO.write正好有个write(BufferedImage img,String format,OutputStream output) 4.真的舒服,我就用它了! 实际情况: 1.Linux环境centos6.8 虚拟化环境 2.JRE1.8 3.接口工作流程:(1) 生成BufferedImage (2)BufferedImage通过ImageIO.write(BufferedImage,"png",ByteArrayOutputStream out) (3)将ByteArrayOutputStream转化为base64 (4) 接口返回 4.一个普通的链接,生成二维码并返回base6...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- 2048小游戏-低调大师作品
- CentOS8编译安装MySQL8.0.19
- Hadoop3单机部署,实现最简伪集群
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题