使用AOP保护您的方法


在本文中,我们将学习如何以简单的方式保护我们的方法!

我们基本上使用前咨询 面向方面编程(AOP)来实现我们的目标。这篇文章甚至说明了使用AOP来实现诸如安全之类的横切关注点是多么容易。 让我们开始吧

先决条件:

  • 熟悉Spring框架。
  • AOP概述

什么是AOP? Spring AOP支持在Spring应用程序中进行面向方面的编程。在AOP中,各方面可以实现关注点的模块化,例如事务管理,日志记录或跨多种类型和对象的安全性(通常称为“横切关注点”)。

什么是Advice? 咨询是一个方面在特定的连接点处采取的措施。不同类型的建议包括“周围”,“之前”和“之后”建议。

什么是Before advice? 在建议之前:在连接点之前执行的建议,但是它不能阻止执行流程前进到连接点(除非它引发异常)。

以下代码段显示了 SecureMessage该类。这是我们将使用AOP进行保护的类。

public class SecureMessage
{
  public void writeSecureMessage() 
  {
    System.out.println("100 pushup and 100 situp is the key to success-Saitama");
  }
}

由于此示例要求用户进行身份验证,因此我们将需要存储其详细信息。以下代码段显示了UserInfo可用于存储用户凭据的类:

public class SecurityManager {
  private static ThreadLocal<UserInfo>
  threadLocal = new ThreadLocal<>();
  public void login(String userName, String password) {
    threadLocal.set(new UserInfo(userName, password));
  }
  public void logout() {
    threadLocal.set(null);
  }
  public UserInfo getLoggedOnUser() {
    return threadLocal.get();
  }
}

请注意,在实际的应用程序中,该 login() 方法可能会根据数据库或LDAP目录检查提供的凭据,但是在这里,我们将根据静态值进行检查和分配。

login():方法UserInfo 为用户创建一个 对象,并使用ThreadLocal将其存储在当前线程中。 logout():方法将可能存储在其中的任何值设置 ThreadLocal 为null。 getLoggedOnUser():方法返回UserInfo当前已验证用户的 对象。如果未验证任何用户,则此方法返回null。 现在我们来看看有趣的东西。

要检查用户是否通过身份验证,如果要通过身份验证,则是否需要允许用户访问SecureMessage上的方法,我们需要创建在该方法之前执行的 建议,并根据SecurityManager.getLoggedOnUser()返回的UserInfo对象进行检查。允许用户的凭证。该建议的代码SecurityAdvice如下所示:

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class SecurityAdvice implements MethodBeforeAdvice {
  private SecurityManager securityManager;
  public SecurityAdvice() {
    this.securityManager = new SecurityManager();
  }
  @Override
  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(
      "You must login before attempting to invoke the method: "
      + method.getName());
    } else if ("Saitama".equals(user.getUserName())) {
        System.out.println("Logged in user is Saitama - OKAY!");
    } else {
      System.out.println("Logged in user is " + user.getUserName()
      + " NOT GOOD :(");
      throw new SecurityException("User " + user.getUserName()
      + " is not allowed access to method " + method.getName());
  }
}

before()方法,我们执行简单的检查以查看通过身份验证的用户的用户名是否为琦玉。如果是这样,我们允许用户访问;否则,将引发异常。还要注意,我们检查了一个空的UserInfo对象,该对象指示当前用户未通过身份验证。

在以下代码片段中,您可以看到一个使用SecurityAdvice类保护SecureMessage类的示例应用程序:

import org.springframework.aop.framework.ProxyFactory;

public class SecurityDemo {
    public static void main(String... args) {
        SecurityManager mgr = new SecurityManager();
        SecureMessage bean = getSecureBean();
        mgr.login("Saitama", "pwd");
        System.out.println("---Scenario 1---");
        bean.writeSecureMessage();
        mgr.logout();
        try {
            mgr.login("invalid user", "pwd");
            System.out.println("---Scenario 2---");
            bean.writeSecureMessage();
        } catch (SecurityException ex) {
            System.out.println("Exception Caught: " + ex.getMessage());
        } finally {
            mgr.logout();
        }
        try {
            System.out.println("---Scenario 3---");
            bean.writeSecureMessage();
        } catch (SecurityException ex) {
            System.out.println("Exception Caught: " + ex.getMessage());
        }
    }

    private static SecureBean getSecureBean() {
        SecureMessage target = new SecureMessage();
        SecurityAdvice advice = new SecurityAdvice();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target);
        factory.addAdvice(advice);
        SecureMessage proxy = (SecureMessage) factory.getProxy();
        return proxy;
    }
}

输出: -场景1 ---

登录的用户是琦玉-好的!

100俯卧撑和100仰卧起坐是成功的关键-Sa玉

-场景2 ---

登录的用户是无效的用户NOT GOOD。

引发异常:不允许用户无效的用户访问方法writeSecureMessage

---方案3 ---未 验证用户

引发异常:您必须先登录才能尝试调用方法:writeSecureMessage

概述 在该 getSecureBean()方法中,我们创建一个SecureMessage 使用SecurityAdvice实例建议的类的代理 。该代理返回给调用者。当调用方调用此代理上的任何方法时,该调用首先被路由到SecurityAdvice实例以进行安全检查。在该 main() 方法中,我们测试了三种情况,分别SecureMessage.writeSecureMessage() 使用两组用户凭据和根本没有用户凭据的方式调用该 方法。因为SecurityAdvice仅当当前经过身份验证的用户是Saitama时,才允许进行方法调用,所以我们可以预期,先前代码中唯一成功的方案是第一个成功方案。

如您所见,只有第一个调用 SecureMessage.writeSecureMessage()被允许进行。剩余的调用被SecurityException 抛出的异常 阻止 SecurityAdvice。这个例子很简单,但是它确实突出了事前建议的有用性。安全性是先验建议的典型示例,但是当场景需要修改传递给方法的参数时,我们也发现它很有用。


原文链接:http://codingdict.com