Spring Cloud OAuth 无Token调用源码封装

背景

重构-改善既有代码的设计,重构的目的是是软件更容易被理解和修改。

书接上回Spring Security OAuth 微服务内部Token传递的源码解析,本篇主要无token 调用过程中,代码的不断完善及其重构过程。

需求很简单如下图,如果资源服务器的提供的接口,客户端不需要身份验证即不需要携带合法令牌也能访问,并且可以实现远程调用的安全性校验.

在这里插入图片描述

第一版本

资源服务器设置接口permitall,配置ignore url 即可

ignore-urls:
- /actuator/**
- /v2/api-docs

在这里插入图片描述
保证A对外暴露,A --> B 暴露的服务接口安全

自定义 @Inner
校验逻辑,判断接口请求中是否含有 XX 请求头

/**
 * @author lengleng
 * <p>
 * 服务间接口不鉴权处理逻辑
 */
@Slf4j
@Aspect
@Component
@AllArgsConstructor
public class PigxSecurityInnerAspect {
	private final HttpServletRequest request;

	@SneakyThrows
	@Around("@annotation(inner)")
	public Object around(ProceedingJoinPoint point, Inner inner) {
		String header = request.getHeader(SecurityConstants.FROM);
		if (inner.value() && !StrUtil.equals(SecurityConstants.FROM_IN, header)) {
			log.warn("访问接口 {} 没有权限", point.getSignature().getName());
			throw new AccessDeniedException("Access is denied");
		}
		return point.proceed();
	}

}

网关请求含有XX 的请求头,避免伪造

public class PigxRequestGlobalFilter implements GlobalFilter, Ordered {
	private static final String HEADER_NAME = "X-Forwarded-Prefix";

	/**
	 * Process the Web request and (optionally) delegate to the next
	 * {@code WebFilter} through the given {@link GatewayFilterChain}.
	 *
	 * @param exchange the current server exchange
	 * @param chain    provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// 1. 清洗请求头中from 参数
		ServerHttpRequest request = exchange.getRequest().mutate()
			.headers(httpHeaders -> {httpHeaders.remove(SecurityConstants.FROM);})
			.build();
		return chain.filter(exchange.mutate()
				.request(newRequest.mutate()
						.header(HEADER_NAME, basePath)
						.build()).build());
	}

	@Override
	public int getOrder() {
		return -1000;
	}
}

接口使用,首先声明 B服务的这个接口对外暴露
ignore-urls:

  • /info/*
    接口使用,然后在 B服务的这个接口 添加@Inner注解

    @Inner
    @GetMapping("/info/{username}")
    public R info(@PathVariable String username) {

    }

重构

上边第一版本的问题是,对于A/B 资源服务想对外暴露的接口,需要两步
声明在ResourceServerConfigurerAdapter 的 permitall
B服务要再次添加@inner 注解
实现@Inner 一步到位到位

在ignoreU日历 获取全部Controller 中,标志@Inner 注解的请求,自动维护到忽略的URL,减少开发配置

public class PermitAllUrlProperties implements InitializingBean {
	private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
	@Autowired
	private WebApplicationContext applicationContext;

	@Getter
	@Setter
	private List<String> ignoreUrls = new ArrayList<>();

	@Override
	public void afterPropertiesSet() {
		RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
		Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();

		map.keySet().forEach(info -> {
			HandlerMethod handlerMethod = map.get(info);

			// 获取方法上边的注解 替代path variable 为 *
			Inner method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Inner.class);
			Optional.ofNullable(method)
					.ifPresent(inner -> info.getPatternsCondition().getPatterns()
							.forEach(url -> ignoreUrls.add(ReUtil.replaceAll(url, PATTERN, StringPool.ASTERISK))));
		});

	}
}

核心是通过RequestMappingHandlerMapping 获取全部的路由配置,然后对 Requestmappint 设置的URL 进行规则替换,然后添加到 ignoreurl中,然后在注入到 ResourceServerConfigurerAdapter 进行permitall
使用时候,如果是外部暴露
@Inner(value=false)
如果仅是服务内部调用暴露
@Inner

加java高级架构师群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。
性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限
都是大牛带飞 让你少走很多的弯路的 群号是: 798891710对了 小白勿进 最好是有开发经验

猜你喜欢

转载自blog.csdn.net/zhuguang10/article/details/89553137