安全性中的Spring AOP –通过方面控制UI组件的创建

以下文章将显示在我参与的一个项目中,我们如何使用Spring的AOP来介绍一些与安全性相关的功能。 这样的概念是为了使用户能够看到一些UI组件,他需要具有一定级别的安全特权。 如果不满足该要求,则不会显示UIComponent。 让我们看一下项目结构:

然后还有aopApplicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

 <aop:aspectj-autoproxy />
 <context:annotation-config />
 <context:component-scan base-package="pl.grzejszczak.marcin.aop">
  <context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
 </context:component-scan>
 <bean class="pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor" factory-method="aspectOf"/> 

</beans>

现在,让我们看一下Spring应用程序上下文中最有趣的几行。 首先,我们拥有所有必需的模式-我认为不需要对此进行更深入的解释。 然后我们有:

<aop:aspectj-autoproxy/>

启用@AspectJ支持。 接下来是

<context:annotation-config />
<context:component-scan base-package="pl.grzejszczak.marcin.aop">
    <context:exclude-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>

首先,我们通过注释打开Spring配置。 然后,我们故意排除了由Spring本身将其初始化为Bean的方面。 为什么? 因为…

<bean class="pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor" factory-method="aspectOf"/>

我们希望自己创建方面,并提供factory-method =” aspectOf”。 这样,我们的方面将包含在我们的bean的自动装配过程中-因此,所有带有@Autowired注释的字段都将注入bean。 现在让我们继续执行代码:

UserServiceImpl.java

package pl.grzejszczak.marcin.aop.service;

import org.springframework.stereotype.Service;

import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.user.UserHolder;

@Service
public class UserServiceImpl implements UserService {
 private UserHolder userHolder;

 @Override
 public UserHolder getCurrentUser() {
  return userHolder;
 }

 @Override
 public void setCurrentUser(UserHolder userHolder) {
  this.userHolder = userHolder;
 }

 @Override
 public Role getUserRole() {
  if (userHolder == null) {
   return null;
  }
  return userHolder.getUserRole();
 }
}

UserServiceImpl类正在模仿一种服务,该服务将从数据库或当前应用程序上下文中获取当前用户信息。

UserHolder.java

package pl.grzejszczak.marcin.aop.user;

import pl.grzejszczak.marcin.aop.type.Role;

public class UserHolder {
 private Role userRole;

 public UserHolder(Role userRole) {
  this.userRole = userRole;
 }

 public Role getUserRole() {
  return userRole;
 }

 public void setUserRole(Role userRole) {
  this.userRole = userRole;
 }
}

这是一个简单的持有人类,其中包含有关当前用户角色的信息。

角色.java

package pl.grzejszczak.marcin.aop.type;

public enum Role {
 ADMIN("ADM"), WRITER("WRT"), GUEST("GST");

 private String name;

 private Role(String name) {
  this.name = name;
 }

 public static Role getRoleByName(String name) {

  for (Role role : Role.values()) {

   if (role.name.equals(name)) {
    return role;
   }
  }

  throw new IllegalArgumentException("No such role exists [" + name + "]");
 }

 public String getName() {
  return this.name;
 }

 @Override
 public String toString() {
  return name;
 }
}

角色是一个枚举,它为管理员作家来宾定义了一个角色。

UIComponent.java

package pl.grzejszczak.marcin.aop.ui;

public abstract class UIComponent {
 protected String componentName;

 protected String getComponentName() {
  return componentName;
 }

}

一些UI组件的具体实现的抽象。

SomeComponentForAdminAndGuest.java

package pl.grzejszczak.marcin.aop.ui;

import pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation;
import pl.grzejszczak.marcin.aop.type.Role;

@SecurityAnnotation(allowedRole = { Role.ADMIN, Role.GUEST })
public class SomeComponentForAdminAndGuest extends UIComponent {

 public SomeComponentForAdminAndGuest() {
  this.componentName = "SomeComponentForAdmin";
 }

 public static UIComponent getComponent() {
  return new SomeComponentForAdminAndGuest();
 }
}

此组件是UI组件扩展的示例,只有拥有AdminGuest角色的用户才能看到。

SecurityAnnotation.java

package pl.grzejszczak.marcin.aop.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import pl.grzejszczak.marcin.aop.type.Role;

@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityAnnotation {
 Role[] allowedRole();
}

定义可以创建此组件的角色的注释。

UIFactoryImpl.java

package pl.grzejszczak.marcin.aop.ui;

import org.apache.commons.lang.NullArgumentException;
import org.springframework.stereotype.Component;

@Component
public class UIFactoryImpl implements UIFactory {

 @Override
 public UIComponent createComponent(Class<? extends UIComponent> componentClass) throws Exception {
  if (componentClass == null) {
   throw new NullArgumentException("Provide class for the component");
  }
  return (UIComponent) Class.forName(componentClass.getName()).newInstance();
 }
}

给定扩展UIComponent的对象类的工厂类将返回给定UIComponent的新实例。

SecurityInterceptor.java

package pl.grzejszczak.marcin.aop.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.List;

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation;
import pl.grzejszczak.marcin.aop.service.UserService;
import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.ui.UIComponent;

@Aspect
public class SecurityInterceptor {
 private static final Logger LOGGER = LoggerFactory.getLogger(SecurityInterceptor.class);

 public SecurityInterceptor() {
  LOGGER.debug("Security Interceptor created");
 }

 @Autowired
 private UserService userService;

 @Pointcut("execution(pl.grzejszczak.marcin.aop.ui.UIComponent pl.grzejszczak.marcin.aop.ui.UIFactory.createComponent(..))")
 private void getComponent(ProceedingJoinPoint thisJoinPoint) {
 }

 @Around("getComponent(thisJoinPoint)")
 public UIComponent checkSecurity(ProceedingJoinPoint thisJoinPoint) throws Throwable {
  LOGGER.info("Intercepting creation of a component");

  Object[] arguments = thisJoinPoint.getArgs();
  if (arguments.length == 0) {
   return null;
  }

  Annotation annotation = checkTheAnnotation(arguments);
  boolean securityAnnotationPresent = (annotation != null);

  if (securityAnnotationPresent) {
   boolean userHasRole = verifyRole(annotation);
   if (!userHasRole) {
    LOGGER.info("Current user doesn't have permission to have this component created");
    return null;
   }
  }
  LOGGER.info("Current user has required permissions for creating a component");
  return (UIComponent) thisJoinPoint.proceed();
 }

 /**
  * Basing on the method's argument check if the class is annotataed with
  * {@link SecurityAnnotation}
  * 
  * @param arguments
  * @return
  */
 private Annotation checkTheAnnotation(Object[] arguments) {
  Object concreteClass = arguments[0];
  LOGGER.info("Argument's class - [{}]", new Object[] { arguments });
  AnnotatedElement annotatedElement = (AnnotatedElement) concreteClass;
  Annotation annotation = annotatedElement.getAnnotation(SecurityAnnotation.class);
  LOGGER.info("Annotation present - [{}]", new Object[] { annotation });
  return annotation;
 }

 /**
  * The function verifies if the current user has sufficient privilages to
  * have the component built
  * 
  * @param annotation
  * @return
  */
 private boolean verifyRole(Annotation annotation) {
  LOGGER.info("Security annotation is present so checking if the user can use it");
  SecurityAnnotation annotationRule = (SecurityAnnotation) annotation;
  List<Role> requiredRolesList = Arrays.asList(annotationRule.allowedRole());
  Role userRole = userService.getUserRole();
  return requiredRolesList.contains(userRole);
 }
}

这是在执行函数createComponent的切入点处定义的方面
UIFactory接口。 在“ 环绕” 建议中,存在一种逻辑,该逻辑首先检查将什么样的参数传递给方法createComponent(例如SomeComponentForAdminAndGuest.class)。 接下来,检查此类是否用SecurityAnnotation进行注释,如果是,它将检查创建组件所需的角色类型。 然后,它检查当前用户(从UserService到UserHolder的Roles)是否具有呈现组件所需的角色。 如果是这样的话 调用thisJoinPoint.proceed(),实际上返回扩展UIComponent的类的对象。 现在让我们对其进行测试-SpringJUnit4ClassRunner来了

AopTest.java

package pl.grzejszczak.marcin.aop;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import pl.grzejszczak.marcin.aop.service.UserService;
import pl.grzejszczak.marcin.aop.type.Role;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForAdmin;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForAdminAndGuest;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForGuest;
import pl.grzejszczak.marcin.aop.ui.SomeComponentForWriter;
import pl.grzejszczak.marcin.aop.ui.UIFactory;
import pl.grzejszczak.marcin.aop.user.UserHolder;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:aopApplicationContext.xml" })
public class AopTest {

 @Autowired
 private UIFactory uiFactory;

 @Autowired
 private UserService userService;

 @Test
 public void adminTest() throws Exception {
  userService.setCurrentUser(new UserHolder(Role.ADMIN));
  Assert.assertNotNull(uiFactory.createComponent(SomeComponentForAdmin.class));
  Assert.assertNotNull(uiFactory.createComponent(SomeComponentForAdminAndGuest.class));
  Assert.assertNull(uiFactory.createComponent(SomeComponentForGuest.class));
  Assert.assertNull(uiFactory.createComponent(SomeComponentForWriter.class));
 }
}

和日志:

pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:26 Security Interceptor created
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForAdmin]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[ADM])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:70 Current user has required permissions for creating a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForAdminAndGuest]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[ADM, GST])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:70 Current user has required permissions for creating a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForGuest]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[GST])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:66 Current user doesn't have permission to have this component created
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:38 Intercepting creation of a component
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:48 Argument's class - [[class pl.grzejszczak.marcin.aop.ui.SomeComponentForWriter]]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:54 Annotation present - [@pl.grzejszczak.marcin.aop.annotation.SecurityAnnotation(allowedRole=[WRT])]
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:57 Security annotation is present so checking if the user can use it
pl.grzejszczak.marcin.aop.interceptor.SecurityInterceptor:66 Current user doesn't have permission to have this component created

单元测试表明,对于给定的Admin角色,仅创建了前两个组件,而对于其他两个,则返回null(由于用户没有适当的权限)。 这就是在我们的项目中,我们如何使用Spring的AOP创建一个简单的框架,该框架将检查用户是否可以创建给定的组件。 由于对这些方面进行了编程,因此不必记住编写任何与安全相关的代码,因为它将为他完成。


翻译自: https://www.javacodegeeks.com/2013/04/spring-aop-in-security-controlling-creation-of-ui-components-via-aspects.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值