Spring AOP(面向切面程式設計)能將權限檢查、日誌、交易等橫切關注點與業務邏輯解耦。本範例示範如何使用 MethodBeforeAdvice 在方法執行前驗證使用者身分,僅允許特定帳號存取受保護方法。
aop.secure
├── UserInfo.java // 使用者資料模型
├── SecureBean.java // 受保護的業務元件
├── SecurityAdvice.java // 切面:方法前置通知
├── SecurityManager.java // 登入/登出狀態管理
└── SecurityExample.java // 測試入口
package aop.secure;
public class UserInfo {
private String userName;
private String password;
public UserInfo(String userName, String password) {
this.userName = userName;
this.password = password;
}
public String getUserName() { return userName; }
public String getPassword() { return password; }
}
package aop.secure;
public class SecureBean {
public void writeSecureMessage() {
System.out.println("Every time I learn something new and it pushes some old stuff out of my brain.");
}
}
package aop.secure;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class SecurityAdvice implements MethodBeforeAdvice {
private SecurityManager securityManager = new SecurityManager();
public void before(Method method, Object[] args, Object target) throws Throwable {
UserInfo user = securityManager.getLoggedOnUser();
if (user == null) {
System.out.println("No user authenticated.");
throw new SecurityException("Method name: " + method.getName());
} else if ("chigo".equals(user.getUserName()) && "chigo".equals(user.getPassword())) {
System.out.println("OKAY! Access granted.");
} else {
System.out.println("Logged in user is: " + user.getUserName());
throw new SecurityException("User " + user.getUserName() + " is not allowed access to method " + method.getName());
}
}
}
package aop.secure;
public class SecurityManager {
private static ThreadLocal<UserInfo> local = new ThreadLocal<UserInfo>();
public void login(String userName, String password) {
local.set(new UserInfo(userName, password));
}
public void logout() { local.set(null); }
public UserInfo getLoggedOnUser() { return local.get(); }
}
package aop.secure;
import org.springframework.aop.framework.ProxyFactory;
public class SecurityExample {
private static SecureBean getSecureBean() {
SecureBean target = new SecureBean();
SecurityAdvice advice = new SecurityAdvice();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvice(advice);
return (SecureBean) pf.getProxy();
}
public static void main(String[] args) {
SecurityManager mgr = new SecurityManager();
SecureBean bean = getSecureBean();
// 合法使用者
mgr.login("chigo", "chigo");
bean.writeSecureMessage(); // 成功
mgr.logout();
// 非法使用者
try {
mgr.login("kkk", "");
bean.writeSecureMessage();
} catch (SecurityException ex) {
System.out.println("Exception caught: " + ex.getMessage());
} finally {
mgr.logout();
}
// 未登入
try {
bean.writeSecureMessage();
} catch (SecurityException ex) {
System.out.println("Exception caught: " + ex.getMessage());
}
}
}
OKAY! Access granted.
Every time I learn something new and it pushes some old stuff out of my brain.
Logged in user is: kkk
Exception caught: User kkk is not allowed access to method writeSecureMessage
No user authenticated.
Exception caught: Method name: writeSecureMessage
@AspectJ 註解風格(Spring 2.0+),減少 XML 配置。AfterReturningAdvice 或 ThrowsAdvice 實現存取稽核日誌。