原文地址:http://haohaoxuexi.iteye.com/blog/2247057
所有的Authentication实现类都保存了一个GrantedAuthority列表,其表示用户所具有的权限。GrantedAuthority是通过AuthenticationManager设置到Authentication对象中的,然后AccessDecisionManager将从Authentication中获取用户所具有的GrantedAuthority来鉴定用户是否具有访问对应资源的权限。
GrantedAuthority是一个接口,其中只定义了一个getAuthority()方法,其返回值为String类型。该方法允许AccessDecisionManager获取一个能够精确代表该权限的字符串。通过返回一个字符串,一个GrantedAuthority能够很轻易的被大部分AccessDecisionManager读取。如果一个GrantedAuthority不能够精确的使用一个String来表示,那么其对应的getAuthority()方法调用应当返回一个null,这表示AccessDecisionManager必须对该GrantedAuthority的实现有特定的支持,从而可以获取该GrantedAuthority所代表的权限信息。
spring Security内置了一个GrantedAuthority的实现,SimpleGrantedAuthority。它直接接收一个表示权限信息的字符串,然后getAuthority()方法直接返回该字符串。Spring Security内置的所有AuthenticationProvider都是使用它来封装Authentication对象的。
1.2 调用前的处理
Spring Security是通过拦截器来控制受保护对象的访问的,如方法调用和Web请求。在正式访问受保护对象之前,Spring Security将使用AccessDecisionManager来鉴定当前用户是否有访问对应受保护对象的权限。
1.2.1AccessDecisionManager
AccessDecisionManager是由AbstractSecurityInterceptor调用的,它负责鉴定用户是否有访问对应资源(方法或URL)的权限。AccessDecisionManager是一个接口,其中只定义了三个方法,其定义如下。
public interface AccessDecisionManager {
/**
* 通过传递的参数来决定用户是否有访问对应受保护对象的权限
*
* @param authentication 当前正在请求受包含对象的Authentication
* @param object 受保护对象,其可以是一个MethodInvocation、JoinPoint或FilterInvocation。
* @param configAttributes 与正在请求的受保护对象相关联的配置属性
*
*/
void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException;
/**
* 表示当前AccessDecisionManager是否支持对应的ConfigAttribute
*/
boolean supports(ConfigAttribute attribute);
/**
* 表示当前AccessDecisionManager是否支持对应的受保护对象类型
*/
boolean supports(Class<?> clazz);
}
decide()方法用于决定authentication是否符合受保护对象要求的configAttributes。supports(ConfigAttribute attribute)方法是用来判断AccessDecisionManager是否能够处理对应的ConfigAttribute的。supports(Class<?> clazz)方法用于判断配置的AccessDecisionManager是否支持对应的受保护对象类型。
1.2.2基于投票的AccessDecisionManager实现
Spring Security已经内置了几个基于投票的AccessDecisionManager,当然如果需要你也可以实现自己的AccessDecisionManager。以下是Spring Security官方文档提供的一个图,其展示了与基于投票的AccessDecisionManager实现相关的类。
使用这种方式,一系列的AccessDecisionVoter将会被AccessDecisionManager用来对Authentication是否有权访问受保护对象进行投票,然后再根据投票结果来决定是否要抛出AccessDeniedException。AccessDecisionVoter是一个接口,其中定义有三个方法,具体结构如下所示。
public interface AccessDecisionVoter<S> {
intACCESS_GRANTED = 1;
intACCESS_ABSTAIN = 0;
intACCESS_DENIED = -1;
boolean supports(ConfigAttribute attribute);
boolean supports(Class<?> clazz);
int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
}
vote()方法的返回结果会是AccessDecisionVoter中定义的三个常量之一。ACCESS_GRANTED表示同意,ACCESS_DENIED表示返回,ACCESS_ABSTAIN表示弃权。如果一个AccessDecisionVoter不能判定当前Authentication是否拥有访问对应受保护对象的权限,则其vote()方法的返回值应当为弃权ACCESS_ABSTAIN。
Spring Security内置了三个基于投票的AccessDecisionManager实现类,它们分别是AffirmativeBased、ConsensusBased和UnanimousBased。
AffirmativeBased的逻辑是这样的:
(1)只要有AccessDecisionVoter的投票为ACCESS_GRANTED则同意用户进行访问;
(2)如果全部弃权也表示通过;
(3)如果没有一个人投赞成票,但是有人投反对票,则将抛出AccessDeniedException。
ConsensusBased的逻辑是这样的:
(1)如果赞成票多于反对票则表示通过。
(2)反过来,如果反对票多于赞成票则将抛出AccessDeniedException。
(3)如果赞成票与反对票相同且不等于0,并且属性allowIfEqualGrantedDeniedDecisions的值为true,则表示通过,否则将抛出异常AccessDeniedException。参数allowIfEqualGrantedDeniedDecisions的值默认为true。
(4)如果所有的AccessDecisionVoter都弃权了,则将视参数allowIfAllAbstainDecisions的值而定,如果该值为true则表示通过,否则将抛出异常AccessDeniedException。参数allowIfAllAbstainDecisions的值默认为false。
UnanimousBased的逻辑与另外两种实现有点不一样,另外两种会一次性把受保护对象的配置属性全部传递给AccessDecisionVoter进行投票,而UnanimousBased会一次只传递一个ConfigAttribute给AccessDecisionVoter进行投票。这也就意味着如果我们的AccessDecisionVoter的逻辑是只要传递进来的ConfigAttribute中有一个能够匹配则投赞成票,但是放到UnanimousBased中其投票结果就不一定是赞成了。UnanimousBased的逻辑具体来说是这样的:
(1)如果受保护对象配置的某一个ConfigAttribute被任意的AccessDecisionVoter反对了,则将抛出AccessDeniedException。
(2)如果没有反对票,但是有赞成票,则表示通过。
(3)如果全部弃权了,则将视参数allowIfAllAbstainDecisions的值而定,true则通过,false则抛出AccessDeniedException。
1.2.2.1RoleVoter
RoleVoter是Spring Security内置的一个AccessDecisionVoter,其会将ConfigAttribute简单的看作是一个角色名称,在投票的时如果拥有该角色即投赞成票。如果ConfigAttribute是以“ROLE_”开头的,则将使用RoleVoter进行投票。当用户拥有的权限中有一个或多个能匹配受保护对象配置的以“ROLE_”开头的ConfigAttribute时其将投赞成票;如果用户拥有的权限中没有一个能匹配受保护对象配置的以“ROLE_”开头的ConfigAttribute,则RoleVoter将投反对票;如果受保护对象配置的ConfigAttribute中没有以“ROLE_”开头的,则RoleVoter将弃权。
1.2.2.2AuthenticatedVoter
AuthenticatedVoter也是Spring Security内置的一个AccessDecisionVoter实现。其主要用来区分匿名用户、通过Remember-Me认证的用户和完全认证的用户。完全认证的用户是指由系统提供的登录入口进行成功登录认证的用户。
AuthenticatedVoter可以处理的ConfigAttribute有IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED和IS_AUTHENTICATED_ANONYMOUSLY。如果ConfigAttribute不在这三者范围之内,则AuthenticatedVoter将弃权。否则将视ConfigAttribute而定,如果ConfigAttribute为IS_AUTHENTICATED_ANONYMOUSLY,则不管用户是匿名的还是已经认证的都将投赞成票;如果是IS_AUTHENTICATED_REMEMBERED则仅当用户是由Remember-Me自动登录,或者是通过登录入口进行登录认证时才会投赞成票,否则将投反对票;而当ConfigAttribute为IS_AUTHENTICATED_FULLY时仅当用户是通过登录入口进行登录的才会投赞成票,否则将投反对票。
AuthenticatedVoter是通过AuthenticationTrustResolver的isAnonymous()方法和isRememberMe()方法来判断SecurityContextHolder持有的Authentication是否为AnonymousAuthenticationToken或RememberMeAuthenticationToken的,即是否为IS_AUTHENTICATED_ANONYMOUSLY和IS_AUTHENTICATED_REMEMBERED。
1.2.2.3自定义Voter
当然,用户也可以通过实现AccessDecisionVoter来实现自己的投票逻辑。
1.3 调用后的处理
AccessDecisionManager是用来在访问受保护的对象之前判断用户是否拥有访问该对象的权限。有的时候我们可能会希望在请求执行完成后对返回值做一些修改,当然,你可以简单的通过AOP来实现这一功能。Spring Security为我们提供了一个AfterInvocationManager接口,它允许我们在受保护对象访问完成后对返回值进行修改或者进行权限鉴定,看是否需要抛出AccessDeniedException,其将由AbstractSecurityInterceptor的子类进行调用。AfterInvocationManager接口的定义如下。
public interface AfterInvocationManager {
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class<?> clazz);
}
以下是Spring Security官方文档提供的一个AfterInvocationManager构造实现的图。
类似于AuthenticationManager,AfterInvocationManager拥有一个默认的实现类AfterInvocationProviderManager,其中拥有一个由AfterInvocationProvider组成的集合,AfterInvocationProvider与AfterInvocationManager具有相同的方法定义,在调用AfterInvocationProviderManager中的方法时实际上就是依次调用其中包含的AfterInvocationProvider对应的方法。
需要注意的是AfterInvocationManager需要在受保护对象成功被访问后才能执行。
1.4 角色的继承
对于角色继承这种需求也是经常有的,比如要求ROLE_ADMIN将拥有所有的ROLE_USER所具有的权限。当然我们可以给拥有ROLE_ADMIN角色的用户同时授予ROLE_USER角色来达到这一效果或者修改需要ROLE_USER进行访问的资源使用ROLE_ADMIN也可以访问。Spring Security为我们提供了一种更为简便的办法,那就是角色的继承,它允许我们的ROLE_ADMIN直接继承ROLE_USER,这样所有ROLE_USER可以访问的资源ROLE_ADMIN也可以访问。定义角色的继承我们需要在ApplicationContext中定义一个RoleHierarchy,然后再把它赋予给一个RoleHierarchyVoter,之后再把该RoleHierarchyVoter加入到我们基于Voter的AccessDecisionManager中,并指定当前使用的AccessDecisionManager为我们自己定义的那个。以下是一个定义角色继承的完整示例。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- 通过access-decision-manager-ref指定将要使用的AccessDecisionManager -->
<security:http access-decision-manager-ref="accessDecisionManager">
<security:form-login/>
<security:intercept-url pattern="/admin.jsp" access="ROLE_ADMIN" />
<security:intercept-url pattern="/**" access="ROLE_USER" />
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="userDetailsService"/>
</security:authentication-manager>
<bean id="userDetailsService"
class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 自己定义AccessDecisionManager对应的bean -->
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref local="roleVoter"/>
</list>
</property>
</bean>
<bean id="roleVoter"
class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy"><!-- 角色继承关系 -->
<value>
ROLE_ADMIN > ROLE_USER
</value>
</property>
</bean>
</beans>
在上述配置中我们就定义好了ROLE_ADMIN是继承自ROLE_USER的,这样ROLE_ADMIN将能够访问所有ROLE_USER可以访问的资源。通过RoleHierarchyImpl的hierarchy属性我们可以定义多个角色之间的继承关系,如:
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy"><!-- 角色继承关系 -->
<value>
ROLE_ADMIN > ROLE_USER
ROLE_A > ROLE_B
ROLE_B > ROLE_C
ROLE_C > ROLE_D
</value>
</property>
</bean>
在上述配置我们同时定义了ROLE_ADMIN继承了ROLE_USER,ROLE_A继承了ROLE_B,ROLE_B又继承了ROLE_C,ROLE_C又继承了ROLE_D,这样ROLE_A将能访问ROLE_B、ROLE_C和ROLE_D所能访问的所有资源。
相关推荐
权限设计(包括表结构) 权限设计是任何系统不可或缺的一部分,对于系统的正常运作和管理起着至关重要的作用。权限设计的主要目标是确保系统中的每个用户都拥有适当的权限,从而确保系统的安全和稳定。 permissions...
在Linux操作系统中,"su"命令用于切换到超级用户(root)权限,这对于执行系统级管理任务至关重要。然而,有时用户可能会遇到"su"鉴定失败的问题,这通常是由以下原因引起的: 1. **未设置ROOT密码**:在安装Linux...
超详细的权限表结构设计pdm, 使用powerdesigner打开即可。
在设计B/S系统的用户权限管理时,数据结构的分析与设计是至关重要的。用户权限管理是确保系统安全、高效运行的基础,特别是在B/S架构中,由于浏览器作为通用客户端的特性,权限控制显得尤为关键,防止未经授权的用户...
我们可以将系统功能分解为七个部分:用户登录、用户资料维护、组织结构调整、权限列表和权限组维护、用户和组织关系维护、用户和权限关系维护、组织和权限关系维护。 在设计数据库时,我们可以遵循以下原则: 1. ...
例如,使用树形结构可以方便地实现权限的层级关系,而哈希表则可以快速查找用户或角色对应的权限集。 在"通用数据权限管理系统设计.doc"中,可能会详细探讨如何设计一个适应性强、易于扩展的权限管理系统。这可能...
系统权限:系统规定用户使用数据库的权限。(系统权限是对用户而言)。 实体权限:某种权限用户对其它用户的表或视图的存取权限。(是针对表或视图而言的)。 二、系统权限管理: 1、系统权限分类: DBA: 拥有全部...
Liferay权限结构是Liferay门户平台中核心的安全机制,它负责控制用户对系统资源的访问和操作。本文档主要针对Liferay的权限系统进行了深入解析,旨在为初学者提供详尽的指导。 首先,我们要理解Liferay权限的定义。...
本项目"easy ui tree 前后端树形结构项目 权限管理demo"提供了一个完整的解决方案,使用了Easy UI Tree库来实现前端的树形结构,并结合SSM(Spring、SpringMVC、MyBatis)框架和MySQL数据库进行后端处理。...
权限设置模块中可根据需要改为:将树型结构的节点写进数据库,进行动态修改。在程序中动态生成树型结构 过系统管理员:sys 密码:sys 普通用户:001 密码:123 用VB、VS等开发工具可参考设计。
在企业运营中,一个清晰、明确的权限结构图至关重要,它可以帮助管理层有效地分配资源,确保工作的顺畅进行。"Excel模板公司各部门权限结构图"是一个实用的工具,用于描绘公司的组织架构以及各个部门和岗位的权限...
部门权限:定义不同部门内的访问权限。 小组权限:细化到小组层面的权限设置。 用户权限:针对单个用户的个性化权限分配。 租户权限:确保每个租户的数据隔离及其相应的访问权限。 3. 权限类型 前端菜单权限:控制...
总结起来,BW报表权限创建涉及到权限对象的定义、权限变量的设置、权限结构的设计以及角色的分配。正确实施这些步骤能确保数据安全,同时提高用户的操作效率。通过深入理解这些知识点,管理员可以更好地控制数据访问...
标题中的"surrounding:分析项目结构,获得权限配置文件"表明这个项目主要涉及的是对一个软件项目的结构进行分析,并且重点关注的是权限配置文件。在Java开发中,权限配置文件通常用于管理系统的访问控制,例如Spring ...
本文将深入探讨svn的权限设置以及本地库目录结构的设计。 首先,svn的权限设置主要通过两种方式实现:一是svnserve配置,二是通过HTTP/HTTPS协议(Apache或IIS)进行WebDAV访问。这里我们主要关注svnserve的权限...
基于springboot+security+jwt+redis实现微信小程序登录及token权限鉴定源码+项目说明.zip springboot+security+jwt+redis 实现微信小程序登录及token权限鉴定 tips:这是实战篇,默认各位看官具备相应的基础(文中使用...
"带checkbox的dtree权限树"是一种常见的实现方式,它结合了数据树(dtree)与复选框(checkbox)功能,用于展示层级关系的权限结构。这种权限树常用于角色分配、用户权限设置以及权限级别的可视化管理。 1. **dtree...
从提供的文件列表来看,我们有两个主要文件:`ssms.sql`,这很可能是SQL脚本,用于创建数据库结构,以及`SSMS`,这可能是项目源代码或相关的应用程序。 首先,让我们深入了解一下Shiro的权限管理。在Shiro中,权限...
系统的模块结构设计包括组权限管理、角色权限管理、用户权限管理、组织管理和操作日志管理五部分。用户界面的实现使用 Java Swing 实现,可以在桌面应用和 Web 应用系统中进行调用。 在系统设计中,我们还需要注意...
9. **权限继承**:在层次结构结构中,子对象可能继承父对象的权限。例如,一个目录下的所有文件可能自动继承该目录的访问控制设置。 10. **审计和日志**:为了跟踪和记录用户活动,权限系统通常会生成审计日志,...