`
jaesonchen
  • 浏览: 313388 次
  • 来自: ...
社区版块
存档分类
最新评论

转载:基于方法的权限控制

 
阅读更多

原文地址:http://haohaoxuexi.iteye.com/blog/2262363

 

      之前介绍的都是基于URL的权限控制,spring Security同样支持对于方法的权限控制。可以通过intercept-methods对某个bean下面的方法进行权限控制,也可以通过pointcut对整个Service层的方法进行统一的权限控制,还可以通过注解定义对单独的某一个方法进行权限控制。

 

1.1     intercept-methods定义方法权限控制

       intercept-methods是需要定义在bean元素下的,通过它可以定义对当前的bean的某些方法进行权限控制,具体方法是使用其下的子元素protect进行定义的。protect元素需要指定两个属性,accessmethodmethod表示需要拦截的方法名称,可以使用通配符,access表示执行对应的方法需要拥有的权限,多个权限之间可以使用逗号分隔。

   <bean id="userService" class="com.xxx.service.impl.UserServiceImpl">

      <security:intercept-methods>

         <security:protect access="ROLE_USER" method="find*"/>

         <security:protect access="ROLE_ADMIN" method="add*"/>

         <security:protect access="ROLE_ADMIN" method="update*"/>

         <security:protect access="ROLE_ADMIN" method="delete*"/>

      </security:intercept-methods>

   </bean>

 

       在上面的配置中表示在执行UserServiceImpl的方法名以find开始的方法时需要当前用户拥有ROLE_USER的权限,在执行方法名以addupdatedelete开始的方法时需要拥有ROLE_ADMIN的权限。当访问被拒绝时还是交由ExceptionTranslationFilter处理,这也就意味着如果用户未登录则会引导用户进行登录,否则默认将返回403错误码到客户端。

 

1.2     使用pointcut定义方法权限控制

       基于pointcut的方法权限控制是通过global-method-security下的protect-pointcut来定义的。可以在global-method-security元素下定义多个protect-pointcut以对不同的pointcut使用不同的权限控制。

   <security:global-method-security>

      <security:protect-pointcut access="ROLE_READ" expression="execution(* com.elim.*..*Service.find*(..))"/>

      <security:protect-pointcut access="ROLE_WRITE" expression="execution(* com.elim.*..*Service.*(..))"/>

   </security:global-method-security>

 

       上面的定义表示我们在执行com.elim包或其子包下任意以Service结尾的类,其方法名以find开始的所有方法时都需要用户拥有ROLE_READ的权限,对于com.elim包或其子包下任意以Service结尾的类的其它方法在执行时都需要ROLE_WRITE的权限。需要注意的是对应的类需要是定义在ApplicationContext中的bean才行。此外同对于URL的权限控制一样,当定义多个protect-pointcut时更具有特性的应当先定义,因为在pointcut匹配的时候是按照声明顺序进行匹配的,一旦匹配上了后续的将不再进行匹配了。

 

1.3     使用注解定义方法权限控制

       基于注解的方法权限控制也是需要通过global-method-security元素定义来进行启用的。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解。这三种注解默认都是没有启用的,需要单独通过global-method-security元素的对应属性进行启用。

 

1.3.1   JSR-250注解

       要使用JSR-250注解,首先我们需要通过设置global-method-security元素的jsr250-annotation=”enabled”来启用基于JSR-250注解的支持,默认为disabled

       <security:global-method-security jsr250-annotations="enabled"/>

 

       此外,还需要确保添加了jsr250-api到我们的类路径下。之后就可以在我们的Service方法上使用JSR-250注解进行权限控制了。

@Service

@RolesAllowed("ROLE_ADMIN")

public class UserServiceImpl implements UserService {

 

   public void addUser(User user) {

      System.out.println("addUser................" + user);

   }

 

   public void updateUser(User user) {

      System.out.println("updateUser.............." + user);

   }

 

   @RolesAllowed({"ROLE_USER", "ROLE_ADMIN"})

   public User find(int id) {

      System.out.println("find user by id............." + id);

      return null;

   }

 

   public void delete(int id) {

      System.out.println("delete user by id................");

   }

 

   @RolesAllowed("ROLE_USER")

   public List<User> findAll() {

      System.out.println("find all user...............");

      return null;

   }

 

}

 

       上面的代码表示执行UserServiceImpl里面所有的方法都需要角色ROLE_ADMIN,其中findAll()方法的执行需要ROLE_USER角色,而find()方法的执行对于ROLE_USER或者ROLE_ADMIN角色都可以。

 

       顺便介绍一下JSR-250中对权限支持的注解。

       RolesAllowed表示访问对应方法时所应该具有的角色。其可以标注在类上,也可以标注在方法上,当标注在类上时表示其中所有方法的执行都需要对应的角色,当标注在方法上表示执行该方法时所需要的角色,当方法和类上都使用了@RolesAllowed进行标注,则方法上的@RolesAllowed将覆盖类上的@RolesAllowed,即方法上的@RolesAllowed将对当前方法起作用。@RolesAllowed的值是由角色名称组成的数组。

       PermitAll表示允许所有的角色进行访问,也就是说不进行权限控制。@PermitAll可以标注在方法上也可以标注在类上,当标注在方法上时则只对对应方法不进行权限控制,而标注在类上时表示对类里面所有的方法都不进行权限控制。(1)当@PermitAll标注在类上,而@RolesAllowed标注在方法上时则按照@RolesAllowed将覆盖@PermitAll,即需要@RolesAllowed对应的角色才能访问。(2)当@RolesAllowed标注在类上,而@PermitAll标注在方法上时则对应的方法也是不进行权限控制的。(3)当在方法上同时使用了@PermitAll@RolesAllowed时先定义的将发生作用,而都定义在类上时则是反过来的,即后定义的将发生作用(这个没多大的实际意义,实际应用中不会有这样的定义)。

       DenyAll是和PermitAll相反的,表示无论什么角色都不能访问。@DenyAll只能定义在方法上。你可能会有疑问使用@DenyAll标注的方法无论拥有什么权限都不能访问,那还定义它干啥呢?使用@DenyAll定义的方法只是在我们的权限控制中不能访问,脱离了权限控制还是可以访问的。

 

1.3.2  @Secured注解

       @Secured是由Spring Security定义的用来支持方法权限控制的注解。它的使用也是需要启用对应的支持才会生效的。通过设置global-method-security元素的secured-annotations=”enabled”可以启用Spring Security对使用@Secured注解标注的方法进行权限控制的支持,其值默认为disabled

   <security:global-method-security secured-annotations="enabled"/>

 

@Service

public class UserServiceImpl implements UserService {

 

   @Secured("ROLE_ADMIN")

   public void addUser(User user) {

      System.out.println("addUser................" + user);

   }

 

   @Secured("ROLE_USER")

   public List<User> findAll() {

      System.out.println("find all user...............");

      return null;

   }

 

}

 

       在上面的代码中我们使用@Secured定义了只有拥有ROLE_ADMIN角色的用户才能调用方法addUser(),只有拥有ROLE_USER角色的用户才能调用方法findAll()

 

1.3.3   支持表达式的注解

       Spring Security中定义了四个支持使用表达式的注解,分别是@PreAuthorize@PostAuthorize@PreFilter@PostFilter。其中前两者可以用来在方法调用前或者调用后进行权限检查,后两者可以用来对集合类型的参数或者返回值进行过滤。要使它们的定义能够对我们的方法的调用产生影响我们需要设置global-method-security元素的pre-post-annotations=”enabled”,默认为disabled

   <security:global-method-security pre-post-annotations="disabled"/>

 

使用@PreAuthorize@PostAuthorize进行访问控制

       @PreAuthorize可以用来控制一个方法是否能够被调用。

@Service

public class UserServiceImpl implements UserService {

 

   @PreAuthorize("hasRole('ROLE_ADMIN')")

   public void addUser(User user) {

      System.out.println("addUser................" + user);

   }

 

   @PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")

   public User find(int id) {

      System.out.println("find user by id............." + id);

      return null;

   }

 

}

       在上面的代码中我们定义了只有拥有角色ROLE_ADMIN的用户才能访问adduser()方法,而访问find()方法需要有ROLE_USER角色或ROLE_ADMIN角色。使用表达式时我们还可以在表达式中使用方法参数。

public class UserServiceImpl implements UserService {

 

   /**

    * 限制只能查询Id小于10的用户

    */

   @PreAuthorize("#id<10")

   public User find(int id) {

      System.out.println("find user by id........." + id);

      return null;

   }

  

   /**

    * 限制只能查询自己的信息

    */

   @PreAuthorize("principal.username.equals(#username)")

   public User find(String username) {

      System.out.println("find user by username......" + username);

      return null;

   }

 

   /**

    * 限制只能新增用户名称为abc的用户

    */

   @PreAuthorize("#user.name.equals('abc')")

   public void add(User user) {

      System.out.println("addUser............" + user);

   }

 

}

       在上面代码中我们定义了调用find(int id)方法时,只允许参数id小于10的调用;调用find(String username)时只允许username为当前用户的用户名;定义了调用add()方法时只有当参数usernameabc时才可以调用。

 

       有时候可能你会想在方法调用完之后进行权限检查,这种情况比较少,但是如果你有的话,Spring Security也为我们提供了支持,通过@PostAuthorize可以达到这一效果。使用@PostAuthorize时我们可以使用内置的表达式returnObject表示方法的返回值。我们来看下面这一段示例代码。

   @PostAuthorize("returnObject.id%2==0")

   public User find(int id) {

      User user = new User();

      user.setId(id);

      return user;

   }

       上面这一段代码表示将在方法find()调用完成后进行权限检查,如果返回值的id是偶数则表示校验通过,否则表示校验失败,将抛出AccessDeniedException       需要注意的是@PostAuthorize是在方法调用完成后进行权限检查,它不能控制方法是否能被调用,只能在方法调用完成后检查权限决定是否要抛出AccessDeniedException

 

使用@PreFilter@PostFilter进行过滤

       使用@PreFilter@PostFilter可以对集合类型的参数或返回值进行过滤。使用@PreFilter@PostFilter时,Spring Security将移除使对应表达式的结果为false的元素。

   @PostFilter("filterObject.id%2==0")

   public List<User> findAll() {

      List<User> userList = new ArrayList<User>();

      User user;

      for (int i=0; i<10; i++) {

         user = new User();

         user.setId(i);

         userList.add(user);

      }

      return userList;

   }

 

       上述代码表示将对返回结果中id不为偶数的user进行移除。filterObject是使用@PreFilter@PostFilter时的一个内置表达式,表示集合中的当前对象。当@PreFilter标注的方法拥有多个集合类型的参数时,需要通过@PreFilterfilterTarget属性指定当前@PreFilter是针对哪个参数进行过滤的。如下面代码就通过filterTarget指定了当前@PreFilter是用来过滤参数ids的。

   @PreFilter(filterTarget="ids", value="filterObject%2==0")

   public void delete(List<Integer> ids, List<String> usernames) {

      ...

   }

 

1.4     方法权限控制的拦截器

       关于方法权限控制,Spring Security提供了两类AbstractSecurityInterceptor,基于AOP AllianceMethodSecurityInterceptor,和基于Aspectj继承自MethodSecurityInterceptorAspectJMethodSecurityInterceptor

 

1.4.1   MethodSecurityInterceptor

       当我们在使用基于NameSpace进行方法保护的配置时,Spring Security默认配置的就是MethodSecurityInterceptor。根据配置的不同,一个拦截器可能只是针对于一个bean,也可能是针对于多个bean的。MethodSecurityInterceptor使用一个MethodSecurityMetadataSource的实例来获取特定方法调用配置的ConfigAttribute。当我们在ApplicationContext配置文件中使用intercept-methods元素或protect-point元素定义需要保护的方法调用时,Spring Security内部默认会使用一个MapBasedMethodSecurityMetadataSource来保存在这些元素上定义的配置信息,保存的key是对应的方法名(可以是含有通配符的)。类似的使用JSR-250注解时将使用Jsr250MethodSecurityMetadataSource解析配置属性;使用@Secured注解时将使用SecuredAnnotationSecurityMetadataSource解析配置属性;使用pre-post-annotations时将使用PrePostAnnotationSecurityMetadataSource解析配置属性。

       MethodSecurityInterceptor是实现了MethodInterceptor接口的,所以我们在使用Spring Aop时,可以自己配置一个MethodSecurityInterceptorbean

 

   <!-- 自定义MethodSecurityInterceptor -->

   <bean id="methodSecurityInterceptor"

   class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">

      <property name="authenticationManager" ref="authenticationManager" />

      <property name="accessDecisionManager" ref="accessDecisionManager" />

      <property name="afterInvocationManager" ref="afterInvocationManager" />

      <property name="securityMetadataSource">

         <security:method-security-metadata-source>

            <!-- 指定需要受保护的方法和需要的权限 -->

            <security:protect method="com.xxx.service.UserService.find*"

                access="ROLE_USER" />

            <security:protect method="com.xxx.service.UserService.delete*"

                access="ROLE_ADMIN" />

         </security:method-security-metadata-source>

      </property>

   </bean>

 

       定义了MethodSecurityInterceptor以后,我们需要类似AOP配置那样,配置哪些该MethodInterceptor需要拦截哪些方法的执行。这种可选配置是很多种的,因为我们这里只是拦截UserService中的具体方法,所以就采用基于bean name的自动代理。

   <!-- 基于bean的拦截 -->

   <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

      <property name="interceptorNames">

         <list>

            <value>methodSecurityInterceptor</value>

         </list>

      </property>

      <property name="beanNames">

         <list>

            <value>userService</value>

         </list>

      </property>

   </bean>

 

       按照上面的配置,我们在访问UserServicefind方法时就需要ROLE_USER的权限,而访问delete方法时则需要ROLE_ADMIN权限。

 

1.4.2   AspectJMethodSecurityInterceptor

       AspectJMethodSecurityInterceptor是继承自MethodSecurityInterceptor的,不同的是AspectJMethodSecurityInterceptor是用来支持AspectJJointPoint的,但在底层还是会把它封装成一个MethodInvocation进行调用。

分享到:
评论

相关推荐

    CRM 权限控制---转载。

    通过以上分析可以看出,在Siebel CRM系统中,权限控制不仅涵盖了传统的用户认证、访问控制等方面,还特别注重于基于角色的访问控制(RBAC)以及视图控制。这样的设计使得组织能够更加灵活地管理其业务流程,同时确保了...

    转载:Android中如何修改系统时间(应用程序获得系统权限)

    Android采用的是基于权限的访问控制模型,每个应用都有自己的沙箱环境,互不干扰。如果一个应用想要执行一些需要特殊权限的操作,比如修改系统时间,它必须在AndroidManifest.xml文件中声明相应的权限。对于修改系统...

    Java利用Preferences设置个人偏好,转载自:燕窝

    Preferences API遵循操作系统的访问控制策略,系统级别的偏好需要管理员权限才能修改,而用户级别的偏好仅限于当前用户。 4. **跨进程共享**: 因为Preferences API是基于文件系统的,所以同一台机器上的不同Java...

    转载VLAN学习手册

    3. **简化管理**:便于网络的管理和维护,可以按部门或功能划分VLAN,便于权限控制和故障定位。 4. **优化性能**:通过流量控制,避免了不必要的跨VLAN通信,提高了网络效率。 四、VLAN的实现 VLAN的实现通常依赖于...

    解析WindowsXP操作系统中的帐户和权限功能

    Windows XP作为一款由微软公司开发的操作系统,相较于其前身Windows 9x系列,引入了更为精细的账户管理和权限控制机制,这主要得益于其基于Windows NT内核的技术架构。 #### 权限与权利:理解基本概念 在Windows...

    一周内学会linux系统管理

    在一周内学会Linux系统管理,你需要掌握一系列关键概念和技能,这些内容涵盖了操作系统的基本操作、文件管理、用户权限、进程控制、网络配置以及系统维护等多个方面。以下是对这些知识点的详细说明: 1. **Linux...

    《转载》oracle1000问

    - 实体授权(Object Privileges):针对单个对象进行权限控制。 7. **高可用性**: - RAC(Real Application Clusters):多节点共享同一数据库,提高可用性和性能。 - Data Guard:主备数据库,实现故障切换和...

    本项目是基于SpringBoot的线上宠物物资购买系统,为个人毕业设计,未经允许禁止转载.zip

    开发者可能已经配置了用户登录、权限控制等功能。 8. **异常处理与日志记录**:SpringBoot支持统一的异常处理机制,并集成了Logback或Log4j等日志框架,便于调试和监控系统状态。 9. **单元测试与集成测试**:为了...

    转载软件测试试题

    - **权限管理不严**:不当的权限设置可能导致敏感信息泄露。 - **搜索功能局限性**:在大量数据中查找特定记录时可能存在困难。 #### 测试用例设计完整过程 测试用例设计是一个系统化的过程,涉及以下步骤: 1. **...

    转载,若依快速开发框架很不错,详情请看https://www.ruoyi.vip/

    Ruoyi 快速开发框架是一款基于Java技术的开源项目,专为提高开发效率而设计。这个框架结合了现代化的前端技术与强大的后端服务,提供了丰富的功能和优秀的用户体验。在RuoYi-Vue-fast-master这个压缩包中,我们可以...

    MITSUBISHI三菱柔性高速I_O控制模块设置工具安装步骤说明书.pdf

    在卸载该工具时,应通过Windows控制面板执行,避免使用其他方法可能导致的问题。 最后,需要注意的是,未经三菱电机株式会社许可,禁止复制或以任何形式转载本说明书的内容。由于软件和硬件的不断更新,说明书可能...

    悠索科技高校教务管理系统(转载)

    6. **权限控制与安全**:考虑到教务管理系统涉及敏感信息,系统可能包含了用户角色、权限分配等功能,以确保数据的安全。 7. **异常处理**:通过使用try-catch语句来捕获和处理运行时可能出现的错误,确保系统的...

    sqlserver学习资料(转载!)

    - 用户、角色和权限:管理数据库访问,控制用户对资源的访问级别。 - 权限和策略:设置访问规则,确保数据安全。 通过这份SQL Server学习资料,你将能够全面了解和掌握SQL Server的各个方面,从基本概念到高级...

    视频监控源码(转载)

    本文将基于提供的"视频监控源码(转载)"进行深入探讨,分析相关知识点。 首先,视频监控系统的核心在于图像采集、传输、存储和分析。源码中可能包含以下几个关键部分: 1. 图像采集:这部分通常涉及摄像头驱动程序...

    转载 纯nasm实现中文操作系统.txt

    具体实现方法未在提供的代码片段中体现,但可以推测可能采用了自定义的中文字符集或编码方案。 #### 3. 内存布局 在`init.asm`文件中提到了系统的内存布局设计,这反映了操作系统的内存管理策略。关键点包括: - ...

    淘宝客C#开源码(转载下载)

    在这个"淘宝客C#开源码(转载下载)"项目中,我们关注的是一个使用C#编程语言开发的微信小程序源代码。C#是一种面向对象的、现代的编程语言,广泛应用于Windows平台的应用程序开发,尤其是微软的.NET框架。 这个...

    Spring-Security-3应用的11个步骤.docx

    Spring Security 是一个强大的和高度可定制的身份验证和访问控制框架,用于保护基于 Java 的应用程序,尤其是J2EE企业级应用。它起源于2003年的Acegi Security,现在是Spring生态系统的组成部分,最新的版本是3.x。...

    JAVA OA平台源码(转载)SPRING BOOT....

    【标题】:“JAVA OA平台源码(转载)SPRING BOOT...” 这个开源项目是一个基于Java技术的OA(Office Automation)管理系统的源代码实现,利用了Spring Boot框架进行开发。Spring Boot是Spring生态中的一个核心组件...

    Spring Security3.1 最新配置实例 (转载)

    Spring Security 提供了基于角色的访问控制(RBAC),允许我们定义角色和权限。配置中,我们可以通过 `http` 配置元素来指定哪些 URL 或方法需要特定的角色才能访问。例如,`**" access="ROLE_ADMIN" /&gt;` 将限制 `/...

Global site tag (gtag.js) - Google Analytics