我想通过使用Spring Boot AOP实现授权方法。最初的想法是,如果从REST调用返回的返回对象未通过授权检查,它将抛出未授权的异常。
我正在这样做:
@Aspect
@Component
public class AuthAspect {
@Around("AllRestExecPoint()")
public Object auth(ProceedingJoinPoint point) throws Throwable {
Object returnObject = point.proceed();
if (!checkAuthorization(returnObject)) {
throw new UnauthException();
}
return returnObject;
}
}
但是,问题是,如果此REST服务将对我的数据库执行一些INSERT或UPDATE,它将在我的授权检查之前提交。因此,UnauthException
将抛出,但事务仍被提交。
我想尝试在proceed()
调用之前手动创建事务并在返回之前提交它的第一次尝试,但是失败了。
@Aspect
@Component
public class AuthAspect {
private final EntityManager em;
@Autowired
public AuthAspect(EntityManager em) {
this.em = em;
}
@Around("AllRestExecPoint()")
public Object auth(ProceedingJoinPoint point) throws Throwable {
em.getTransaction().begin();
Object returnObject = point.proceed();
if (!checkAuthorization(returnObject)) {
throw new UnauthException();
}
em.getTransaction().commit();
return returnObject;
}
}
这将导致java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
。
我在互联网上搜索了一些答案,需要修改web.xml
文件,但是我不想使用xml进行配置。
从标签来看,您正在使用Spring Boot。Spring Boot提供了一个预配置的TransactionTemplate
,如果您手动想要控制事务,可以使用它。
而不是将其EntityManger
注入您的方面并将代码包装在其中。
@Aspect
@Component
public class AuthAspect {
private final TransactionTemplate tx;
public AuthAspect(TransactionTemplate tx) {
this.tx = tx;
}
@Around("AllRestExecPoint()")
public Object auth(ProceedingJoinPoint pjp) throws Throwable {
return tx.execute(ts -> this.executeAuth(pjp));
}
private Object executeAuth(ProceedingJoinPoint pjp) {
Object returnObject;
try {
returnObject = pjp.proceed();
} catch (Throwable t) {
throw new AopInvocationException(t.getMessage(), t);
}
if (!checkAuthorization(returnObject)) {
throw new UnauthException();
}
return returnObject;
}
}
这将在事务内部执行逻辑。我将实际的逻辑移到一个方法上,以便lambda可以是单个方法而不是代码块。(个人偏好/最佳实践)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句