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

关注我

目录
相关文章
|
15天前
|
Java Linux
Springboot 解决linux服务器下获取不到项目Resources下资源
Springboot 解决linux服务器下获取不到项目Resources下资源
|
1月前
|
弹性计算 监控 数据可视化
ecs资源可视化
ecs资源可视化
23 3
|
30天前
|
弹性计算 运维 监控
ECS资源监控
ECS资源监控涉及CPU、内存、磁盘I/O、网络流量、系统负载和进程的关键指标,通过云服务商控制台、监控服务、API与SDK、运维工具进行实时监控和告警设置。支持历史数据查询、事件监控,以及使用Windows资源监视器和Linux系统工具进行操作系统层面监控。全面监控确保ECS实例稳定运行、资源有效利用和问题及时处理。如需特定云服务商的指导,请询问。
31 3
|
3月前
|
安全 Java Spring
Spring Security OAuth 资源服务器认证浅析
【1月更文挑战第18天】之前的几篇文章介绍了如何进行用户认证并向客户端分发 Token,以及 Token 是如何生成的,这篇分析一下,当客户端拿着 Token 去访问资源的时候,资源服务器是如何验证 Token 是否合法的。
51 2
|
3月前
|
机器学习/深度学习 搜索推荐 算法
推荐系统离线评估方法和评估指标,以及在推荐服务器内部实现A/B测试和解决A/B测试资源紧张的方法。还介绍了如何在TensorFlow中进行模型离线评估实践。
推荐系统离线评估方法和评估指标,以及在推荐服务器内部实现A/B测试和解决A/B测试资源紧张的方法。还介绍了如何在TensorFlow中进行模型离线评估实践。
192 0
|
20天前
|
缓存 监控 Linux
服务器中常用的几个资源监控工具整理
【4月更文挑战第2天】服务器中常用的几个资源监控工具整理
361 13
|
1月前
|
JavaScript 前端开发 应用服务中间件
通过域名的方式访问服务器里的资源
通过域名的方式访问服务器里的资源
24 0
|
1月前
|
弹性计算 开发工具 对象存储
ECS实例通过OSS内网地址访问OSS资源
ECS实例通过OSS内网地址访问OSS资源
39 0
|
5月前
|
缓存 安全 算法
Spring Security OAuth 2.0 资源服务器— JWT
Spring Security OAuth 2.0 资源服务器— JWT
230 1
|
2月前
|
弹性计算 安全 API
带你读《从基础到应用云上安全航行指南》——干货长文快收藏!阿里云专家教你如何安全访问和管理ECS资源(1)
带你读《从基础到应用云上安全航行指南》——干货长文快收藏!阿里云专家教你如何安全访问和管理ECS资源(1)
573 2