切面(Aspect)概念:
定义:
切面是一种模块化的方式,用于将横切关注点(cross-cutting concerns)从业务逻辑中分离出来
横切关注点包括日志记录、性能统计、安全性等,它们通常涉及多个对象和方法
主要组成:
1.切入点(Join Point): 在应用程序执行期间的某个特定点,如方法调用、异常抛出等。
2.通知(Advice): 定义在切入点上执行的操作,包括前置、后置、环绕、异常等不同类型的通知。
3.切入点表达式(Pointcut): 用于匹配切入点的表达式,决定在哪些切入点上执行通知。
主要作用:
将横切关注点集中管理,避免散布在各处的重复代码
提高代码的模块化和可维护性
使用例子:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import com.alibaba.fastjson.JSONObject;
import cn.ctg.common.response.ResponseCode;
import cn.ctg.common.response.ResponseData;
import cn.ctg.common.util.UserTokenUtils;
import cn.ctg.common.util.XssUtils;
import cn.hutool.json.JSONUtil;
@Aspect
@Component
public class SecurityAspect {
@Value("${keys.aeskey:-1}")
private String AES_KEY;
@Value("${keys.jwtkey:-1}")
private String JWT_KEY;
@Value("${xss.url:-1}")
private String xxsUrl;
private AntPathMatcher antPathMatcher = new AntPathMatcher();
/**切面*/
@Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")
public void pointCut(){ }
/**
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* cn.ctg.*.controller.*.*(..))")
public Object doAroundHtml(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
HttpServletRequest httpServletRequest = UserTokenUtils.getHttpServletRequest();
String requestURI = httpServletRequest.getRequestURI();
String[] split = xxsUrl.split("\\|");
if(split==null){
return joinPoint.proceed(args);
}
if(pathMatcher(Arrays.asList(split),requestURI)) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
Map<String, Object> map = JSONUtil.parseObj(JSONObject.toJSONString(arg));
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (XssUtils.isStripXSS(entry.getValue().toString())) {
ResponseData<Object> responseData = ResponseData.error(ResponseCode.XSS_CODE_ERROR);
return responseData;
}
}
}
}
return joinPoint.proceed(args);
}
/** 返回参数加密*/
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//执行方法,获取返回值
Object result = joinPoint.proceed();
String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
if(data.equals("{}")){
data = String.valueOf(((ResponseData<?>) result).getData());
}
/** 可以根据注解选择 加密方法 防止统一*/
((ResponseData<?>) result).setEncrypt(true);
return result;
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
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.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import com.alibaba.fastjson.JSONObject;
import cn.ctg.common.response.ResponseCode;
import cn.ctg.common.response.ResponseData;
import cn.ctg.common.util.UserTokenUtils;
import cn.ctg.common.util.XssUtils;
import cn.hutool.json.JSONUtil;
@Aspect
@Component
public class SecurityAspect {
@Value("${keys.aeskey:-1}")
private String AES_KEY;
@Value("${keys.jwtkey:-1}")
private String JWT_KEY;
@Value("${xss.url:-1}")
private String xxsUrl;
private AntPathMatcher antPathMatcher = new AntPathMatcher();
/**切面*/
@Pointcut("@annotation(cn.ctg.common.util.security.CtgDecrypt) || @annotation(cn.ctg.common.util.security.CtgEncrypt)")
public void pointCut(){ }
/**
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* cn.ctg.*.controller.*.*(..))")
public Object doAroundHtml(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
HttpServletRequest httpServletRequest = UserTokenUtils.getHttpServletRequest();
String requestURI = httpServletRequest.getRequestURI();
String[] split = xxsUrl.split("\\|");
if(split==null){
return joinPoint.proceed(args);
}
if(pathMatcher(Arrays.asList(split),requestURI)) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
Map<String, Object> map = JSONUtil.parseObj(JSONObject.toJSONString(arg));
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (XssUtils.isStripXSS(entry.getValue().toString())) {
ResponseData<Object> responseData = ResponseData.error(ResponseCode.XSS_CODE_ERROR);
return responseData;
}
}
}
}
return joinPoint.proceed(args);
}
/** 返回参数加密*/
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//执行方法,获取返回值
Object result = joinPoint.proceed();
String data = JSONUtil.toJsonStr(((ResponseData<?>) result).getData());
if(data.equals("{}")){
data = String.valueOf(((ResponseData<?>) result).getData());
}
/** 可以根据注解选择 加密方法 防止统一*/
((ResponseData<?>) result).setEncrypt(true);
return result;
}
}