All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.icodegarden.nursery.springboot.web.reactive.handler.ReactiveControllerAspect Maven / Gradle / Ivy

The newest version!
package io.github.icodegarden.nursery.springboot.web.reactive.handler;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;

import io.github.icodegarden.nursery.springboot.security.Authentication;
import io.github.icodegarden.nursery.springboot.security.SecurityUtils;
import io.github.icodegarden.nursery.springboot.web.reactive.util.ReactiveWebUtils;

/**
 * 
 * @author Fangfang.Xu
 *
 */
@Aspect
@EnableAspectJAutoProxy
public class ReactiveControllerAspect implements InstantiationAwareBeanPostProcessor {

	/**
	 * 启动检测Controller的方法上是否有ServerWebExchange参数
	 */
	@Override
	public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
		if (beanClass.isAnnotationPresent(RestController.class) || beanClass.isAnnotationPresent(Controller.class)) {
			Method[] methods = beanClass.getDeclaredMethods();
			for (Method method : methods) {
				if (method.isAnnotationPresent(PostMapping.class)//
						|| method.isAnnotationPresent(PutMapping.class)//
						|| method.isAnnotationPresent(GetMapping.class)//
						|| method.isAnnotationPresent(DeleteMapping.class)//
						|| method.isAnnotationPresent(PatchMapping.class)//
						|| method.isAnnotationPresent(RequestMapping.class)//
				) {
					Arrays.asList(method.getParameterTypes()).stream()
							.filter(parameterType -> ServerWebExchange.class.isAssignableFrom(parameterType))
							.findFirst()
							.orElseThrow(() -> new RuntimeException(String.format(
									"Parameter Type of ServerWebExchange must present on Controller Mapping Method [%s.%s()]",
									beanClass.getName(), method.getName())));
				}
			}
		}

		return null;
	}

	@Pointcut("@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Controller)")
	public void pointcut() {
	}

	/**
	 * 因为reactor中的跨线程,WebFilter认证后即使设置到SecurityUtils,也无法在业务代码处获取认证。
* 所以需要使用ServerWebExchange @see ReactiveGatewayPreAuthenticatedAuthenticationFilter 先承载参数,在正式进controller前再设置到SecurityUtils,因为此时线程同步。
* 注意使用@ControllerAdvice虽然原理差不多,但是有些情况下却会出现@ControllerAdvice中的线程和Controller中的线程不是相同的,依然无法达到目的。 */ @Around("pointcut()") public Object doInvoke(ProceedingJoinPoint pjp) throws Throwable { SecurityUtils.setAuthentication(null); ReactiveWebUtils.setExchange(null); Object[] args = pjp.getArgs(); for (Object arg : args) { if (arg == null) { continue; } Class parameterType = arg.getClass(); if (ServerWebExchange.class.isAssignableFrom(parameterType)) { ServerWebExchange exchange = (ServerWebExchange) arg; try { Authentication authentication = (Authentication) exchange.getAttribute("authentication"); if (authentication != null) { SecurityUtils.setAuthentication(authentication); } ReactiveWebUtils.setExchange(exchange); return pjp.proceed(); } finally { /** * 无效方式,因为pjp.proceed()异步的 */ // SecurityUtils.setAuthentication(null); // ReactiveWebUtils.setExchange(null); } } } return pjp.proceed(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy