檢視上篇文章 通用資料級别權限的架構設計與實作(3)-資料清單的權限過濾
,我們開始在原來的基礎上實作單條權記錄的權限控制。
相信前面的清單權限控制,很多系統都可以做到,但如何在上面清單的權限過濾中實作通用性
原理:我們在權限過濾中,通過AOP接截相關記錄,攔截的時候,我們先判斷目前人員是否有角色權限,沒有的話,我們生成查詢權限的SQL,進行權限查找.
1.先定義生成權限的相關注解,相關注解用于權限攔截,及擷取攔截的相關參數.
Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AuthCheck {
/**權限校驗規則
* @return
*/
Class classModel() ;
/**
* 判斷是否IN查詢
* @return
*/
boolean isIn() default true;
}
注解AuthCheck用于定義單條記錄權限攔截的規則
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthParam {
}
AuthParam隻是用于标記哪個參數用于權限校驗.
2.生成權限校驗SQL的類AuthFiledFilter修改
/**
* 生成對一條記錄的權限校限SQL
* @param id
* @param valueList
* @return
*/
public String getAuthSqlIn(Object id, List valueList){
StringBuffer sb = new StringBuffer();
sb.append("select count(1) from ");
sb.append (this.getSalveTableName() );
sb.append(" where ").append(this.getSalveTableField()).append("=").append(id);
sb.append(" and ");
sb.append(this.buildLogicIN(this.getSearchUserField(), valueList));
return sb.toString();
}
/**
* 生成對一條記錄的權限校驗SQL,用EQ
* @param id
* @param userId
* @return
*/
public String getAuthSqlEq(Object id,Object userId){
StringBuffer sb = new StringBuffer();
sb.append("select count(1) from ");
sb.append (this.getSalveTableName() );
sb.append(" where ").append(this.getSalveTableField()).append("=").append(id);
sb.append(" and ");
sb.append( this.getSearchUserField()).append("=").append(userId);
return sb.toString();
}
3.權限攔截判斷的類AuthValidatorUtil的規則增加
//生成校驗的
public static String getAuthModelSql(String classModel, Object id,boolean isIn) {
AuthValidatorModel authValidatorModel = AuthConfig.get(classModel);
if (authValidatorModel == null) {
return "";
}
boolean isAuth = authValidatorModel.getRoles().stream().anyMatch(role -> UserUtil.containRole(role));
if (isAuth) {
return "";
}
String checkAuthSql="";
if (isIn) {
checkAuthSql = authValidatorModel.getAuthFiledFilter().getAuthSqlIn(id, UserUtil.getOrgIds());
} else {
checkAuthSql = authValidatorModel.getAuthFiledFilter().getAuthSqlEq(id, UserUtil.getUserId());
}
return checkAuthSql;
}
4.關鍵對有權限辨別注解的權限攔截
@Aspect
@Order(1)
@Component
public class AuchCheckAspect {
protected final Log logger = LogFactory.getLog(AuchCheckAspect.class);
@Autowired
AuthMapper authMapper;
/**
* 權限校驗
*
* @param joinPoint
* @throws Throwable
*/
@Before(value = "@annotation( com.starmark.auth.anno.AuthCheck)")
public void timeAroundAdvice(JoinPoint joinPoint) throws Throwable {
//相關參數
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
AuthCheck AuthCheck = method.getAnnotation(AuthCheck.class);
String classModel = AuthCheck.classModel().getName();
Assert.notNull(classModel, " 權限校驗模型不允許為空");
Object id = null;
Object[] args = joinPoint.getArgs();
//從方法中擷取相關主鍵校驗參數
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
AuthParam authParam = parameters[i].getAnnotation(AuthParam.class);
if (authParam != null) {
id = args[i];
break;
}
}
AuthValidatorModel authValidatorModel = AuthConfig.get(classModel);
String checkAuthSql = AuthValidatorUtil.getAuthModelSql(classModel,id,AuthCheck.isIn());
if (StringUtils.isNotEmpty(checkAuthSql)) {
boolean isAuth = authMapper.isAuth(checkAuthSql);
if (!isAuth) {
throw new AuthCheckException();
}
}
}
}
這裡提示一下,AuthMapper是我們執行一條生成的SQL方法,是注入一條SQL,因為SQL是我們背景代碼生成的,無須考慮SQL注入的問題
<!-- 生成 SQL判斷有沒有權限-->
<select id="isAuth" resultType="boolean" >
${authSql}
</select>
5.相關權限的功能使用
@GetMapping(value = "/{id}")
@AuthCheck(classModel = SysAuthRole.class)
public Object get(@PathVariable("id") @AuthParam Long id) {
return sysAuthRoleService.get(id);
}
6.測試:
打開有權限的記錄,正常結果如下:

有權限記錄.png
打開沒有權限的記錄,抛出一個無權限的異常。
無權限記錄.png
至此,單條記錄的權限攔截已完成!
個人代碼已經完成,如需要請打賞後通知我。謝謝.
如果你覺得該文章對你有幫助,麻煩點贊。
歡迎繼續檢視下篇文章-
通用資料級别權限的架構設計與實作(5)-總結與延伸思考