在Spring框架中,可以使用面向切面編程(AOP)來實現注解鑒權。這通常涉及到定義一個切面(Aspect),該切面會在方法執行前進行攔截,并根據注解value值來決定是否允許執行該方法。
簡單思路:
權限標識如:"business:project:list" 字段保存在菜單表,用戶表與菜單表關聯。如果自定義注解中的參數值@RequiresPermissions("business:project:list") 存在于當前用戶所擁有的權限中,則該請求允許訪問該方法,否則拒絕。
首先,需要定義一個注解 RequiresPermissions
/*** 權限認證:必須具有指定權限才能進入該方法* * @author digipower**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface RequiresPermissions {/*** 需要校驗的權限碼*/String[] value() default {};}
然后,你需要定義一個切面,該切面會攔截帶有 @RequiresPermissions 注解的方法
import java.lang.reflect.Method;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import com.digipower.component.security.annotation.RequiresLogin;
import com.digipower.component.security.annotation.RequiresPermissions;
import com.digipower.component.security.annotation.RequiresRoles;
import com.digipower.component.security.auth.AuthUtil;/*** 基于 Spring Aop 的注解鑒權*/
@Aspect
@Component
public class AuthAspect {/** 權限標識 */private static final String ALL_PERMISSION = "*:*:*";/*** 構建*/public AuthAspect() {}/*** 聲明AOP簽名*/@Pointcut(@annotation(com.bibo.test.RequiresPermissions))public void pointcut() {}/*** 環繞切入*/@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 獲取簽名MethodSignature signature = (MethodSignature)joinPoint.getSignature();// 校驗 @RequiresPermissions 注解RequiresPermissions requiresPermissions = signature.getMethod().getAnnotation(RequiresPermissions.class);if (requiresPermissions != null) {// 獲取當前用戶的全部權限,可以從redis、Spring Security安全上下文等Set<String> permissionSet = getXX();for (String permission : requiresPermissions.value()) {if (!hasPermission(permissionSet, permission)) {throw new NotPermissionException(permission);}}}try {// 執行原有邏輯Object obj = joinPoint.proceed();return obj;} catch (Throwable e) {throw e;}}/*** 判斷是否包含權限* * @param authorities* 權限列表* @param permission* 權限字符串* @return 用戶是否具備某權限*/public boolean hasPermission(Collection<String> authorities, String permission) {return authorities.stream().filter().anyMatch(x -> ALL_PERMISSION.contains(x) || PatternMatchUtils.simpleMatch(x, permission));}
}
最后,在你的服務或控制器中,你可以使用
@RequiresPermissions注解來標記需要進行鑒權的方法
/*** 查詢列表*/
@RequiresPermissions("business:project:list")
@GetMapping("/list")
public PageDataResult list(BizInfo bizInfo) {...return ..
}
這樣,每當 list 方法被調用時,AuthAspect 會進行鑒權檢查。如果鑒權失敗,將拋出異常或返回錯誤信息,阻止方法的執行。