扩展资源服务器解决oauth2 性能瓶颈

简介: 用户携带token 请求资源服务器资源服务器拦截器 携带token 去认证服务器 调用tokenstore 对token 合法性校验资源服务器拿到token,默认只会含有用户名信息通过用户名调用userdetailsservice.

  • 用户携带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 再去查询一次用户信息

造成问题现象

  1. 如果设置了userDetailsService 即可在spring security 上下文获取用户的全部信息,不设置则只能得到用户名。
  2. 增加了一次查询逻辑,对性能产生不必要的影响

解决问题

  • 扩展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);
    }
}
  • 完成扩展,再来看文章开头的流程图就变成了如下

关注我

目录
相关文章
|
4月前
|
存储 安全 数据管理
服务器违规资源被删,数据定时备份OSS 云存储才是 “救命稻草”
在数字化时代,数据已成为企业与个人的核心资产。然而,服务器违规、硬件故障等问题频发,导致数据丢失、业务中断,甚至造成不可挽回的损失。为保障数据安全与业务连续性,定时备份至关重要。阿里云国际站OSS提供高效、可靠的云存储解决方案,支持自动定时备份,帮助用户轻松应对数据风险。本文详解OSS备份操作步骤与注意事项,助你为数据穿上“防护甲”,实现安全无忧存储。
|
5月前
|
机器学习/深度学习 人工智能 运维
“服务器老是爆?资源老是浪费?试试用 AI 来规划容量!”
“服务器老是爆?资源老是浪费?试试用 AI 来规划容量!”
155 4
|
8月前
|
缓存 人工智能 架构师
释放数据潜力:利用 MCP 资源让大模型读懂你的服务器
MCP(Model Control Protocol)资源系统是将服务器数据暴露给客户端的核心机制,支持文本和二进制两种类型资源。资源通过唯一URI标识,客户端可通过资源列表或模板发现资源,并使用`resources/read`接口读取内容。MCP还支持资源实时更新通知及订阅机制,确保动态数据的及时性。实现时需遵循最佳实践,如清晰命名、设置MIME类型和缓存策略,同时注重安全性,包括访问控制、路径清理和速率限制等。提供的示例代码展示了如何用JavaScript和Python实现资源支持。
928 80
|
6月前
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
305 18
|
9月前
|
自然语言处理 安全 开发工具
分享一个纯净无广、原版操作系统、开发人员工具、服务器等资源免费下载的网站
分享一个纯净无广、原版操作系统、开发人员工具、服务器等资源免费下载的网站
463 4
|
10月前
|
存储 人工智能 并行计算
2025年阿里云弹性裸金属服务器架构解析与资源配置方案
🚀 核心特性与技术创新:提供100%物理机性能输出,支持NVIDIA A100/V100 GPU直通,无虚拟化层损耗。网络与存储优化,400万PPS吞吐量,ESSD云盘IOPS达100万,RDMA延迟<5μs。全球部署覆盖华北、华东、华南及海外节点,支持跨地域负载均衡。典型应用场景包括AI训练、科学计算等,支持分布式训练和并行计算框架。弹性裸金属服务器+OSS存储+高速网络综合部署,满足高性能计算需求。
|
10月前
|
机器学习/深度学习 运维 资源调度
深度学习在资源利用率优化中的应用:让服务器更聪明
深度学习在资源利用率优化中的应用:让服务器更聪明
469 6
|
11月前
|
弹性计算 运维 Kubernetes
使用ACK Edge统一管理多地域的ECS资源
本文介绍如何使用ACK Edge来管理分布在多个地域的ECS资源。
|
10月前
|
弹性计算 运维 Kubernetes
使用ACK Edge统一管理多地域的ECS资源
使用ACK Edge统一管理多地域的ECS资源
205 0

热门文章

最新文章