前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >扩展jwt解决oauth2 性能瓶颈

扩展jwt解决oauth2 性能瓶颈

原创
作者头像
冷冷
修改2019-03-20 09:08:01
1.7K0
修改2019-03-20 09:08:01
举报
文章被收录于专栏:冷冷冷冷

oauth2 性能瓶颈

资源服务器的请求都会被拦截 到认证服务器校验合法性 (如下图)
  • 用户携带token 请求资源服务器
  • 资源服务器拦截器 携带token 去认证服务器 调用tokenstore 对token 合法性校验
  • 资源服务器拿到token,默认只会含有用户名信息
  • 通过用户名调用userdetailsservice.loadbyusername 查询用户全部信息

如上步骤在实际使用,会造成认证中心的负载压力过大,成为造成整个系统瓶颈的关键点。

check-token 过程中涉及的源码
  • 更为详细的源码讲解可以参考我上篇文章《Spring Cloud OAuth2 资源服务器CheckToken 源码解析》
  • check-token 涉及到的核心类
    jwt 生成携带用户详细信息
  • 为什么使用jwt 替代默认的UUID token ?undefined通过jwt 访问资源服务器后,不再使用check-token 过程,通过对jwt 的解析即可实现身份验证,登录信息的传递。减少网络开销,提高整体微服务集群的性能
  • spring security oauth 默认的jwttoken 只含有username,通过扩展TokenEnhancer,实现关键字段的注入到 JWT 中,方便资源服务器使用
代码语言:txt
复制
	@Bean
	public TokenEnhancer tokenEnhancer() {
		return (accessToken, authentication) -> {
			if (SecurityConstants.CLIENT_CREDENTIALS
					.equals(authentication.getOAuth2Request().getGrantType())) {
				return accessToken;
			}

			final Map<String, Object> additionalInfo = new HashMap<>(8);
			PigxUser pigxUser = (PigxUser) authentication.getUserAuthentication().getPrincipal();
			additionalInfo.put("user_id", pigxUser.getId());
			additionalInfo.put("username", pigxUser.getUsername());
			additionalInfo.put("dept_id", pigxUser.getDeptId());
			additionalInfo.put("tenant_id", pigxUser.getTenantId());
			additionalInfo.put("license", SecurityConstants.PIGX_LICENSE);
			((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
			return accessToken;
		};
	}
  • 生成的token 如下,含有关键的字段

重写默认的资源服务器处理行为

  • 不再使用RemoteTokenServices 去掉用认证中心 CheckToken,自定义客户端TokenService
代码语言:txt
复制
@Slf4j
public class PigxCustomTokenServices implements ResourceServerTokenServices {
	@Setter
	private TokenStore tokenStore;

	@Setter
	private DefaultAccessTokenConverter defaultAccessTokenConverter;

	@Setter
	private JwtAccessTokenConverter jwtAccessTokenConverter;
	
	@Override
	public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException {
		OAuth2Authentication oAuth2Authentication = tokenStore.readAuthentication(accessToken);
		UserAuthenticationConverter userTokenConverter = new PigxUserAuthenticationConverter();
		defaultAccessTokenConverter.setUserTokenConverter(userTokenConverter);
		Map<String, ?> map = jwtAccessTokenConverter.convertAccessToken(readAccessToken(accessToken), oAuth2Authentication);
		return defaultAccessTokenConverter.extractAuthentication(map);
	}


	@Override
	public OAuth2AccessToken readAccessToken(String accessToken) {
		return tokenStore.readAccessToken(accessToken);
	}
}
  • 解析jwt 组装成Authentication
代码语言:txt
复制
/**
 * @author lengleng
 * @date 2019-03-17
 * <p>
 * jwt 转化用户信息
 */
public class PigxUserAuthenticationConverter implements UserAuthenticationConverter {
	private static final String USER_ID = "user_id";
	private static final String DEPT_ID = "dept_id";
	private static final String TENANT_ID = "tenant_id";
	private static final String N_A = "N/A";
	
	@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(USER_ID);
			Integer deptId = (Integer) map.get(DEPT_ID);
			Integer tenantId = (Integer) map.get(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;
	}

	private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
		Object authorities = map.get(AUTHORITIES);
		if (authorities instanceof String) {
			return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
		}
		if (authorities instanceof Collection) {
			return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils
					.collectionToCommaDelimitedString((Collection<?>) authorities));
		}
		throw new IllegalArgumentException("Authorities must be either a String or a Collection");
	}
}
  • 资源服务器配置中注入以上配置即可
代码语言:txt
复制
@Slf4j
public class PigxResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {
	@Override
	public void configure(ResourceServerSecurityConfigurer resources) {
		DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
		UserAuthenticationConverter userTokenConverter = new PigxUserAuthenticationConverter();
		accessTokenConverter.setUserTokenConverter(userTokenConverter);

		PigxCustomTokenServices tokenServices = new PigxCustomTokenServices();
		
		// 这里的签名key 保持和认证中心一致
		JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
		converter.setSigningKey("123");
		converter.setVerifier(new MacSigner("123"));
		JwtTokenStore jwtTokenStore = new JwtTokenStore(converter);
		tokenServices.setTokenStore(jwtTokenStore);
		tokenServices.setJwtAccessTokenConverter(converter);
		tokenServices.setDefaultAccessTokenConverter(accessTokenConverter);

		resources
				.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
				.tokenServices(tokenServices);
	}
}

使用JWT 扩展后带来的问题

  • JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
  • 去认证服务器校验的过程就是 通过tokenstore 来控制jwt 安全性的一个方法,去掉Check-token 意味着 jwt token 安全性不可保证
  • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • 为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

关注我

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • oauth2 性能瓶颈
    • 资源服务器的请求都会被拦截 到认证服务器校验合法性 (如下图)
      • check-token 过程中涉及的源码
      • 重写默认的资源服务器处理行为
      • 使用JWT 扩展后带来的问题
        • 关注我
        相关产品与服务
        多因子身份认证
        多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档