一、場景
在使用shiro框架的時候,遇到了這樣的需求:本系統有多個用戶,每個用戶分配不同角色,每個角色的權限也不一致。比如A用戶擁有新聞列表的增刪改查權限,而B用戶只有查看新聞列表的權限,而沒有刪除、新增、修改的權限,此時有3種方案:1、不給B用戶分配刪除、新增、修改的菜單,這樣用戶就無法點擊從而無法操作。2、給B用戶分配菜單,后台中進行增刪改查操作時都要進行權限驗證。 3、給B用戶分配菜單並且進行操作的時候校驗權限。
顯然,第2、3種方案比第1中方案要安全。本系統中使用第二種方案。
二、為什么使用注解+AOP
使用shiro過程中一般都會自定義Realm,Realm主要進行權限和登錄的校驗,當校驗登錄用戶是否有某個權限的時候,有2種方式:1、使用注解 @RequiresPermissions("news:*") 來判斷用戶是否有news的所有權限。 2、使用Subject.isPermitted("news:*") 方法判斷用戶是否有news的所有權限。
這兩種方法的區別在於,第一種:比如當前用戶在新聞列表中刪除某篇新聞,但是該用戶並沒有這種權限,此時會拋出異常,我們需要處理異常即可,但是頁面進行跳轉,我們希望用戶在新聞列進行刪除操作的時候,如果沒有該權限則會彈窗提示,而不是跳轉到統一的異常頁面。 第二種,可以實現第一種的不足,但是沒有第一種方便快捷。
為了綜合上述兩種的有點以及缺點,實現shiro校驗權限時有異常但不刷新頁面,同時以注解的形式使用。
三、實現
實現的效果:需要校驗權限的方法比如刪除方法del(),只要在該方法上添加自定義注解,即可實現上述效果。
3.1 自定義注解
/**
* 類名 :權限控制注解
* 用法 :
* 創建人 : shyroke
* 時間:2018/12/18 10:33
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PermissionAnnotation {
String permissionName();
}
3.2 編寫切面
/**
* 類名 :權限的切面類
* 用法 :
* 創建人 : shyroke
* 時間:2018/12/18 10:38
*/
@Aspect
@Component
public class PermissionAspect {
@Pointcut("@annotation(com.shyroke.daydayzhuan.util.PermissionAnnotation)")
private void permisson(){
}
/**
* 給添加PermissionAnnotation注解的方法校驗權限,而不必每個方法內都判斷權限
* @param joinPoint
* @param permissionAnnotation
* @return
* @throws Throwable
*/
@Around("permisson()&&@annotation(permissionAnnotation)")
public Object advice(ProceedingJoinPoint joinPoint, PermissionAnnotation permissionAnnotation) throws Throwable {
R r = null;
r = (R) joinPoint.proceed();
String permissionName =permissionAnnotation.permissionName();
if(StringUtils.isEmpty(permissionName)){
r.setFlag(false);
r.setMessage("權限名稱不能為空");
return r;
}
//校驗當前登錄用戶是否有該權限
boolean isPermission = UserUtils.isPermission(permissionName);
if(!isPermission){
r.setFlag(false);
r.setMessage("沒有此操作權限!");
}
return r;
}
}
UserUtils.java
/**
* 類名 :用戶的工具類
* 用法 :
* 創建人 : shyroke
* 時間:2018/12/18 14:39
*/
public class UserUtils {
/**
* 校驗當前登錄用戶是否有該權限
* @param permissionname 權限名稱
* @return
*/
public static boolean isPermission(String permissionname) {
Subject subject = SecurityUtils.getSubject();
if(subject.isPermitted(permissionname)){
return true;
}else{
return false;
}
}
}
3.3 使用
@PermissionAnnotation(permissionName = "boke:*")
@PostMapping(value = "desc")
@ResponseBody
public R desc(){
return R.ok("刪除成功!");
}
3.4 結果

