傳統權限檢查硬編碼在 Action/Service 方法中,導致:代碼重複、業務邏輯混雜、角色變更需全量改代碼。本文採用 Spring AOP + 自定義註解 + Struts2 全局異常映射 實現聲明式權限控制:開發者僅需在方法上標註 @UserAccessAnnotation(isLogin=YES),框架自動攔截驗證,無權限則拋出異常跳轉登錄頁。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UserAccessAnnotation {
ISLOGIN isLogin(); // 枚舉:YES/LOGOUT/NO
}
@Aspect
public class SystemArchitecture {
@Pointcut("@annotation(com.example.annotation.UserAccessAnnotation)")
public void userAccess() {}
}
@Aspect
public class PermissionAspect extends BaseAction {
@Before(value="com.example.aspect.SystemArchitecture.userAccess() && @annotation(userAccessAnnotation)",
argNames="userAccessAnnotation")
public void checkPermission(UserAccessAnnotation userAccessAnnotation) {
ISLOGIN required = userAccessAnnotation.isLogin();
if (!authService.userLogin(getCurrentUser()).equals(required.toString())) {
throw new NoPermissionException(getText("user_no_permission_error"));
}
}
}
argNames 將註解實例綁定為切面方法參數,實現動態權限判斷。
<aop:aspectj-autoproxy/>
<bean id="permission" class="com.example.aspect.PermissionAspect" scope="prototype">
<property name="authService" ref="AuthService"/>
</bean>
<global-exception-mappings>
<exception-mapping exception="com.example.exceptions.NoPermissionException" result="loginerror"/>
</global-exception-mappings>
<global-results>
<result name="loginerror">/WEB-INF/jsp/login.jsp</result>
</global-results>
roles()、permissions() 數組屬性,切面中委託 AuthService 完成 RBAC 校驗Spring AOP 基於 JDK 動態代理/CGLIB,**僅攔截 public 方法的外部調用**;同類內部調用、非 public 方法、final 方法均失效。解決方案:AopContext.currentProxy() 獲取代理引用,或改用 AspectJ LTW(Load-Time Weaving)。
該方案以 「註解聲明 + AOP 攔截 + 異常統一處理」 三層結構,實現權限邏輯與業務代碼零耦合,單人維護註解與切面即可管控全站權限,顯著降低開發成本與維護複雜度。