对于最新的稳定版本,请使用 Spring Security 6.4.3! |
授权架构
当局
Authentication
中,讨论了所有Authentication
implementations 存储一个GrantedAuthority
对象。
这些权限表示已授予委托人的权限。
这GrantedAuthority
对象将插入到Authentication
object 的AuthenticationManager
,稍后由AuthorizationManager
在做出授权决策时。
GrantedAuthority
是一个只有一个方法的接口:
String getAuthority();
此方法允许AuthorizationManager
s 来获得精确的String
表示GrantedAuthority
.
通过将表示形式作为String
一个GrantedAuthority
大多数人都可以轻松“阅读”AuthorizationManager
s 和AccessDecisionManager
s.
如果GrantedAuthority
不能精确地表示为String
这GrantedAuthority
被视为“复杂”,并且getAuthority()
必须返回null
.
“复杂”示例GrantedAuthority
将是一个实现,用于存储适用于不同客户账号的作和权限阈值列表。
代表这个综合体GrantedAuthority
作为String
将非常困难,因此getAuthority()
method 应返回null
.
这将向任何AuthorizationManager
它需要专门支持GrantedAuthority
实现,以便理解其内容。
Spring Security 包括一个具体的GrantedAuthority
实现SimpleGrantedAuthority
.
这允许任何用户指定的String
转换为GrantedAuthority
.
都AuthenticationProvider
包含在安全架构使用中SimpleGrantedAuthority
要填充Authentication
对象。
调用前处理
Spring Security 提供了拦截器,这些拦截器控制对安全对象(例如方法调用或 Web 请求)的访问。
关于是否允许继续调用的调用前决定由AccessDecisionManager
.
The AuthorizationManager
AuthorizationManager
取代两者AccessDecisionManager
和AccessDecisionVoter
.
自定义AccessDecisionManager
或AccessDecisionVoter
鼓励更改为使用AuthorizationManager
.
AuthorizationManager
由AuthorizationFilter
并负责做出最终的访问控制决策。
这AuthorizationManager
interface 包含两个方法:
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
throws AccessDeniedException {
// ...
}
这AuthorizationManager
的check
方法传递它所需的所有相关信息,以便做出授权决策。
特别是,将安全的Object
允许检查实际安全对象调用中包含的那些参数。
例如,假设安全对象是一个MethodInvocation
.
查询MethodInvocation
对于任何Customer
参数,然后在AuthorizationManager
以确保允许 Principal 对该客户进行作。
实现应返回正AuthorizationDecision
如果授予访问权限,则为负数AuthorizationDecision
如果访问被拒绝,并且 nullAuthorizationDecision
当放弃做决定时。
verify
调用check
并随后抛出一个AccessDeniedException
如果出现负数AuthorizationDecision
.
基于委托的 AuthorizationManager 实现
虽然用户可以实现自己的AuthorizationManager
为了控制授权的所有方面,Spring Security 附带了一个委托AuthorizationManager
可以与个人协作AuthorizationManager
s.
RequestMatcherDelegatingAuthorizationManager
将请求与最合适的委托人匹配AuthorizationManager
.
为了方法安全性,您可以使用AuthorizationManagerBeforeMethodInterceptor
和AuthorizationManagerAfterMethodInterceptor
.
授权管理器实现说明了相关的类。
使用这种方法,将AuthorizationManager
可以在授权决策时轮询 implementations。
权限授权管理器
最常见的AuthorizationManager
与 Spring Security 一起提供的是AuthorityAuthorizationManager
.
它配置了一组给定的权限,以在当前的Authentication
.
它将返回正值AuthorizationDecision
如果Authentication
包含任何已配置的权限。
它将返回一个负数AuthorizationDecision
否则。
已验证的授权管理器
另一个 Manager 是AuthenticatedAuthorizationManager
.
它可用于区分匿名用户、完全身份验证用户和经过记住我身份验证的用户。
许多站点允许在 remember-me 身份验证下进行某些受限访问,但需要用户通过登录来确认其身份才能获得完全访问权限。
自定义授权管理器
显然,您还可以实现自定义AuthorizationManager
而且你几乎可以在其中放置任何你想要的访问控制逻辑。
它可能特定于您的应用程序 (与业务逻辑相关),或者它可能实现一些安全管理逻辑。
例如,您可以创建可以查询 Open Policy Agent 或您自己的授权数据库的实现。
您可以在 Spring 网站上找到一篇博客文章,其中描述了如何使用 legacyAccessDecisionVoter 实时拒绝账户被暂停的用户访问。
您可以通过实施来实现相同的结果AuthorizationManager 相反。 |
调整 AccessDecisionManager 和 AccessDecisionVoters
上一页AuthorizationManager
,Spring Security 发布AccessDecisionManager
和AccessDecisionVoter
.
在某些情况下,例如迁移较旧的应用程序,可能需要引入AuthorizationManager
这会调用AccessDecisionManager
或AccessDecisionVoter
.
调用现有的AccessDecisionManager
,您可以执行以下作:
-
Java
@Component
public class AccessDecisionManagerAuthorizationManagerAdapter implements AuthorizationManager {
private final AccessDecisionManager accessDecisionManager;
private final SecurityMetadataSource securityMetadataSource;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
try {
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
this.accessDecisionManager.decide(authentication.get(), object, attributes);
return new AuthorizationDecision(true);
} catch (AccessDeniedException ex) {
return new AuthorizationDecision(false);
}
}
@Override
public void verify(Supplier<Authentication> authentication, Object object) {
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
this.accessDecisionManager.decide(authentication.get(), object, attributes);
}
}
然后将其连接到您的SecurityFilterChain
.
或者只调用AccessDecisionVoter
,您可以执行以下作:
-
Java
@Component
public class AccessDecisionVoterAuthorizationManagerAdapter implements AuthorizationManager {
private final AccessDecisionVoter accessDecisionVoter;
private final SecurityMetadataSource securityMetadataSource;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, Object object) {
Collection<ConfigAttributes> attributes = this.securityMetadataSource.getAttributes(object);
int decision = this.accessDecisionVoter.vote(authentication.get(), object, attributes);
switch (decision) {
case ACCESS_GRANTED:
return new AuthorizationDecision(true);
case ACCESS_DENIED:
return new AuthorizationDecision(false);
}
return null;
}
}
然后将其连接到您的SecurityFilterChain
.
分层角色
一个常见的要求是,应用程序中的特定角色应该自动 “包含” 其他角色。 例如,在具有 “admin” 和 “user” 角色概念的应用程序中,您可能希望 admin 能够执行普通用户可以执行的所有作。 为此,您可以确保所有管理员用户也都分配了 “user” 角色。 或者,您可以修改每个访问约束,这要求 “user” 角色也包括 “admin” 角色。 如果您的应用程序中有很多不同的角色,这可能会变得相当复杂。
使用 role-hierarchy 允许您配置哪些角色(或权限)应包含其他角色。
Spring Security 的RoleVoter
,RoleHierarchyVoter
配置了RoleHierarchy
,从中获取分配给用户的所有“可访问的权限”。
典型的配置可能如下所示:
-
Java
-
Xml
@Bean
AccessDecisionVoter hierarchyVoter() {
RoleHierarchy hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
"ROLE_STAFF > ROLE_USER\n" +
"ROLE_USER > ROLE_GUEST");
return new RoleHierarchyVoter(hierarchy);
}
<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_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST
</value>
</property>
</bean>
这里我们在层次结构中有四个角色ROLE_ADMIN ⇒ ROLE_STAFF ⇒ ROLE_USER ⇒ ROLE_GUEST
.
通过ROLE_ADMIN
将表现得好像它们具有所有四个角色时,当根据AuthorizationManager
适于调用上述RoleHierarchyVoter
.
该符号可以被认为是“包含”的意思。>
角色层次结构提供了一种简便的方法,可以简化应用程序的访问控制配置数据和/或减少需要分配给用户的权限数量。 对于更复杂的要求,您可能希望在应用程序所需的特定访问权限和分配给用户的角色之间定义一个逻辑映射,并在加载用户信息时在两者之间进行转换。
旧版授权组件
Spring Security 包含一些旧组件。 由于它们尚未删除,因此包含文档以用于历史目的。 他们推荐的替代品如上所述。 |
The AccessDecisionManager
这AccessDecisionManager
由AbstractSecurityInterceptor
并负责做出最终的访问控制决策。
这AccessDecisionManager
interface 包含三种方法:
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
这AccessDecisionManager
的decide
方法传递它所需的所有相关信息,以便做出授权决策。
特别是,将安全的Object
允许检查实际安全对象调用中包含的那些参数。
例如,假设安全对象是一个MethodInvocation
.
查询MethodInvocation
对于任何Customer
参数,然后在AccessDecisionManager
以确保允许 Principal 对该客户进行作。
实现应抛出AccessDeniedException
如果访问被拒绝。
这supports(ConfigAttribute)
方法由AbstractSecurityInterceptor
以确定AccessDecisionManager
可以处理传递的ConfigAttribute
.
这supports(Class)
方法,以确保配置的AccessDecisionManager
支持安全侦听器将呈现的安全对象的类型。
基于投票的 AccessDecisionManager 实现
虽然用户可以实现自己的AccessDecisionManager
为了控制授权的所有方面,Spring Security 包括多个AccessDecisionManager
基于 vote 的实现。Voting Decision Manager 说明了相关的类。

使用这种方法,一系列AccessDecisionVoter
实施在授权决策时进行轮询。
这AccessDecisionManager
然后决定是否抛出AccessDeniedException
根据其对选票的评估。
这AccessDecisionVoter
interface 有三种方法:
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
具体实现返回一个int
,可能的值将反映在AccessDecisionVoter
静态字段ACCESS_ABSTAIN
,ACCESS_DENIED
和ACCESS_GRANTED
.
投票实现将返回ACCESS_ABSTAIN
如果它对授权决定没有意见。
如果它确实有观点,则必须返回ACCESS_DENIED
或ACCESS_GRANTED
.
有三种具体AccessDecisionManager
s 提供的 Spring Security 来统计选票。
这ConsensusBased
implementation 将根据非弃权票的共识授予或拒绝访问权限。
提供属性以控制在票数相等或所有投票都弃权的情况下的行为。
这AffirmativeBased
implementation 将授予访问权限(如果有一个或多个ACCESS_GRANTED
已收到投票(即,如果至少有一个授权投票,则将忽略拒绝投票)。
与ConsensusBased
implementation 中,有一个参数控制所有选民弃权时的行为。
这UnanimousBased
提供商期望 UnanimousACCESS_GRANTED
投票以授予访问权限,忽略弃权。
如果有的话,它将拒绝访问ACCESS_DENIED
投票。
与其他实现一样,有一个参数控制所有选民弃权时的行为。
可以实现自定义AccessDecisionManager
这以不同的方式计算选票。
例如,来自特定AccessDecisionVoter
可能会获得额外的权重,而来自特定选民的拒绝投票可能具有否决权。
角色投票者
最常用的AccessDecisionVoter
Spring Security 是简单的RoleVoter
,它将配置属性视为简单的角色名称,如果已为用户分配了该角色,则投票授予访问权限。
如果有的话,它将进行投票ConfigAttribute
以前缀开头ROLE_
.
如果存在GrantedAuthority
,它返回一个String
表示形式(通过getAuthority()
方法)正好等于一个或多个ConfigAttributes
以前缀开头ROLE_
.
如果没有任何ConfigAttribute
起始于ROLE_
这RoleVoter
将投票拒绝访问。
如果没有ConfigAttribute
开头为ROLE_
,则选民将弃权。
已验证的选民
我们隐晦地看到的另一个投票者是AuthenticatedVoter
,可用于区分匿名用户、经过完全身份验证的用户和经过 Remember-me 身份验证的用户。
许多站点允许在 remember-me 身份验证下进行某些受限访问,但需要用户通过登录来确认其身份才能获得完全访问权限。
当我们使用IS_AUTHENTICATED_ANONYMOUSLY
为了授予匿名访问权限,此属性由AuthenticatedVoter
.
有关更多信息,请参阅此类的 Javadoc。
自定义选民
显然,您还可以实现自定义AccessDecisionVoter
而且你几乎可以在其中放置任何你想要的访问控制逻辑。
它可能特定于您的应用程序 (与业务逻辑相关),或者它可能实现一些安全管理逻辑。
例如,您可以在 Spring Web 站点上找到一篇博客文章,该文章描述了如何使用投票者实时拒绝帐户被暂停的用户的访问。

与 Spring Security 的许多其他部分一样,AfterInvocationManager
具有单个具体实现,AfterInvocationProviderManager
,它会轮询AfterInvocationProvider
s.
每AfterInvocationProvider
可以修改 return 对象或抛出AccessDeniedException
.
事实上,多个提供程序可以修改对象,因为前一个提供程序的结果会传递给列表中的下一个提供程序。
请注意,如果您使用的是AfterInvocationManager
,您仍然需要允许MethodSecurityInterceptor
的AccessDecisionManager
以允许作。
如果您使用的是典型的 Spring Security 包括AccessDecisionManager
实现中,如果没有为特定的安全方法调用定义配置属性,将导致每个AccessDecisionVoter
弃权。
反过来,如果AccessDecisionManager
属性 “allowIfAllAbstainDecisions” 为false
一AccessDeniedException
将被抛出。
您可以通过 (i) 将 “allowIfAllAbstainDecisions” 设置为true
(尽管通常不建议这样做)或 (ii) 只需确保至少有一个配置属性AccessDecisionVoter
将投票授予访问权限。
后一种(推荐)方法通常是通过ROLE_USER
或ROLE_AUTHENTICATED
configuration 属性。