1、註解的使用
@PermRequired(params = {@Param(index = 0)}, biz = PermBizCategory.PRODUCT, role = PermRoleGroup.OWNERANDCHILDANDOEM)
public void xxx(String productId, ...) {
...
}
2、註解接口定義
package com.xxx;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) //表示該註解在運行時期仍可以起作用
@Target({ ElementType.METHOD }) //表示該註解只能應用在方法上
public @interface PermRequired {
/**
* 權限業務分類
*
* @return
*/
PermBizCategory biz() default PermBizCategory.GATEWAY;
/**
* 權限分組
*
* @return
*/
PermRoleGroup role() default PermRoleGroup.SHARER;
/**
* 權限控制參數
*
* @return
*/
Param[] params() default {};
/**
* 使用新的驗證方式,不再使用之前註解的方式驗證
* @see
* @return
*/
boolean useNewAuth() default false;
}
3、定義參數類型枚舉
package com.xxx;
@AllArgsConstructor
@Getter
public enum PermBizCategory {
PRODUCT("product", "產品相關業務"),
;
private String value;
private String description;
PermBizCategory(String value, String description) {
this.value = value;
this.description = description;
}
public String getValue() {
return value;
}
}
package com.xxx;
public enum PermRoleGroup {
OWNER("owner", "擁有者"),
OWNERANDCHILD("ownerandchild", "擁有者和子帳號"),
OWNERANDCHILDANDOEM("ownerandchildandoem", "擁有者、子帳號和oem關係所有者"),
OWNERANDCHILDNOTOPERATION("ownerandchildnotoperate","擁有者和子帳號,但是沒有操作"),
;
private String value;
private String description;
PermRoleGroup(String value, String description) {
this.value = value;
this.description = description;
}
public String getValue() {
return value;
}
}
4、切面
package com.xxx;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
@Component
@Aspect
public class PermRequiredAspect {
@Resource
private PermVerifierFactory permVerifierFactory;
@Around("@annotation(com.xxx.PermRequired)")
public Object handlePermission(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
Object[] args = pjp.getArgs();
PermRequired[] permRequireds = method.getAnnotationsByType(PermRequired.class);
for (PermRequired permRequired : permRequireds){
PermBizCategory bizCategory = permRequired.biz();
IPermVerifier permVerifier = permVerifierFactory.getPermVerifier(bizCategory);
permVerifier.verifyPerm(pjp, args, permRequired);
}
Object retVal = pjp.proceed();
return retVal;
}
}
5、業務處理工廠類
package com.xxx;
import com.xxx.ProductPermVerifier;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class PermVerifierFactory implements ApplicationContextAware {
private ApplicationContext applicationContext;
public IPermVerifier getPermVerifier(PermBizCategory bizCategory) {
if (PermBizCategory.PRODUCT.equals(bizCategory)) {
return applicationContext.getBean("productPermVerifier", ProductPermVerifier.class);
} else {
throw new IllegalStateException("unexpected bizCategory");
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
6、Verifier接口及其基類
package com.xxx;
import org.aspectj.lang.ProceedingJoinPoint;
public interface IPermVerifier {
void verifyPerm(ProceedingJoinPoint pjp, Object[] args, PermRequired permRequired) throws Throwable;
}
package com.xxx;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tuya.atop.client.domain.api.ApiRequestDO;
import ognl.Ognl;
import ognl.OgnlException;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public abstract class BasePermVerifier implements IPermVerifier {
protected static final Logger logger = LoggerFactory.getLogger(BasePermVerifier.class);
protected static final Object NA = null;
protected Object getParamValue(Object[] args, Param param)
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, OgnlException {
int index = param.index();
if (index < 0 || index >= args.length) {
return NA;
}
ParamType type = param.type();
if (ParamType.PRIMITIVE == type) {
return args[index];
} else if (ParamType.BEAN == type) {
if (args[index] == null) {
return NA;
} else {
return BeanUtils.getProperty(args[index], param.property());
}
} else if (ParamType.JSON == type) {
if (StringUtils.isBlank((String) args[index])) {
return NA;
} else {
JSONObject jsonObject = JSONObject.parseObject((String) args[index]);
if (jsonObject != null) {
return Ognl.getValue(param.property(), jsonObject);
} else {
return NA;
}
}
} else if (ParamType.JSONARRAY_STRING == type) {
if (StringUtils.isBlank((String) args[index])) {
return NA;
} else {
JSONArray jsonArray = JSONObject.parseArray((String) args[index]);
if (jsonArray != null) {
return jsonArray;
} else {
return NA;
}
}
} else if (ParamType.MAP == type) {
if (args[index] == null) {
return NA;
} else {
return ((Map) args[index]).get(param.property());
}
}
return null;
}
}
7、產品業務Verifier
package com.tuya.crius.atop.perm.verifier;
import ognl.OgnlException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
@Component
public class ProductPermVerifier extends BasePermVerifier {
@Override
public void verifyPerm(ProceedingJoinPoint pjp, Object[] args, PermRequired permRequired) throws Throwable {
PermBizCategory bizCategory = permRequired.biz();
if (PermBizCategory.PRODUCT.equals(bizCategory)) {
Param[] params = permRequired.params();
String productId = (String) getParamValue(args, params[0]);
checkProductPerm(productId, args, permRequired);
} else {
throw new IllegalStateException("unexpected bizCategory");
}
}
protected void checkProductPerm(String productId, Object[] args, PermRequired permRequired)
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, OgnlException {
PermRoleGroup roleGroup = permRequired.role();
if (PermRoleGroup.OWNER.equals(roleGroup)) {
...
} else if (PermRoleGroup.OWNERANDCHILD.equals(roleGroup)) {
...
} else if (PermRoleGroup.OWNERANDCHILDNOTOPERATION.equals(roleGroup)) {
...
} else if (PermRoleGroup.OWNERANDCHILDANDOEM.equals(roleGroup)) {
...
}
else {
logger.error("check perm deny={unexpected role=" + roleGroup + "}");
throw new PermissionDeniedException();
}
}
}