HTTP 接口鑒權(quán)
需求描述:
- 可以定制地為某些指定的 HTTP RESTful api 提供權(quán)限驗(yàn)證功能.
- 當(dāng)調(diào)用方的權(quán)限不符時(shí), 返回錯(cuò)誤.
根據(jù)上面所提出的需求, 我們可以進(jìn)行如下設(shè)計(jì):
- 提供一個(gè)特殊的注解 AuthChecker, 這個(gè)是一個(gè)方法注解, 有此注解所標(biāo)注的 Controller 需要進(jìn)行調(diào)用方權(quán)限的認(rèn)證.
- 利用 Spring AOP, 以 @annotation 切點(diǎn)標(biāo)志符來(lái)匹配有注解 AuthChecker 所標(biāo)注的 joinpoint.
- 在 advice 中, 簡(jiǎn)單地檢查調(diào)用者請(qǐng)求中的 Cookie 中是否有我們指定的 token, 如果有, 則認(rèn)為此調(diào)用者權(quán)限合法, 允許調(diào)用, 反之權(quán)限不合法, 范圍錯(cuò)誤.
1.自定義AuthChecker注解
代碼示例
@Target(ElementType.method)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthChecker{
}
2.自定義切面類(lèi)
代碼示例
@Aspect
@Componet
public class AopAdvise{
// 定義一個(gè)切點(diǎn) 那些方法必須要進(jìn)行攔截
@Pointcut("@annotation(com.zjzcc.xys.demo.AuthChecker)")
public void pointcut(){
}
// 定義一個(gè)Advise
@Around("pointcut()")
public Object checkAuth(ProceedingJoinPoint joint){
// TODO 業(yè)務(wù)邏輯自己實(shí)現(xiàn)
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
return joint.procees();
}
}
方法調(diào)用日志
首先假設(shè)我們有如下需求:
- 某個(gè)服務(wù)下的方法的調(diào)用需要有 log: 記錄調(diào)用的參數(shù)以及返回結(jié)果.
- 當(dāng)方法調(diào)用出異常時(shí), 有特殊處理, 例如打印異常 log, 報(bào)警等.
代碼示例
@Componet
@Aspect
public class LogAspect{
private Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("within(NeedLogService)")
public void pointcut(){
}
@Before("pointcut()")
public void logMethodInvokeParam(JoinPoint joinPoint){
logger.info("方法名:{},參數(shù)名:{}",joinpoint.getSignature().toString,joinpoint.getArgs());
}
@AfterReturning(pointcut = "pointcut()",returning = "retVal")
public void logMethodResultInvoke(JoinPoint joinpoint,Object retVal){
logger.info("方法名:{},參數(shù)名:{}",joinpoint.getSignature().toString,joinpoint.getArgs());
}
@AfterThrowing(pointcut = "pointcut",throwing = "exception")
public void logMethodException(JointPoint joint,Exception ex){
logger.info("方法名:{},異常信息:{}",joinpoint.getSignature().toString,ex.getMessage());
}
}
方法統(tǒng)計(jì)耗時(shí)
代碼示例
@Component
@Aspect
@Order(1)
public class ExpireAspect {
private Logger logger = LoggerFactory.getLogger(getClass());
@Pointcut("within(com.leyou.user.service.UserService)")
public void pointcut(){
}
@Around("pointcut()")
public Object methodInvokeParam(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 開(kāi)始執(zhí)行切入點(diǎn)里面的方法
Object proceed = joinPoint.proceed();
stopWatch.stop();
logger.info("統(tǒng)計(jì)耗時(shí):{}",stopWatch.prettyPrint());
return proceed;
}
}