对于最新的稳定版本,请使用 Spring Security 6.4.1! |
授权架构
当局
Authentication
,讨论所有 implementations 如何存储对象列表。
这些权限表示已授予委托人的权限。
这些对象由 插入到对象中,稍后在做出授权决策时由 读取。Authentication
GrantedAuthority
GrantedAuthority
Authentication
AuthenticationManager
AuthorizationManager
GrantedAuthority
是一个只有一个方法的接口:
String getAuthority();
此方法允许 s 获得 的精确表示。
通过将表示形式返回为 a ,大多数 s 和 s 可以很容易地 “读取” a。
如果 a 不能精确表示为 a ,则认为 为 “复杂” ,必须返回 。AuthorizationManager
String
GrantedAuthority
String
GrantedAuthority
AuthorizationManager
AccessDecisionManager
GrantedAuthority
String
GrantedAuthority
getAuthority()
null
“复杂”的一个示例是存储适用于不同客户账号的操作和权限阈值列表的实现。
将此复杂数表示为 a 将非常困难,因此该方法应返回 。
这将向任何人表明,它需要专门支持实现才能理解其内容。GrantedAuthority
GrantedAuthority
String
getAuthority()
null
AuthorizationManager
GrantedAuthority
Spring Security 包括一个具体的实现 。
这允许将任何用户指定的 .
安全体系结构中包含的所有 都用于填充对象。GrantedAuthority
SimpleGrantedAuthority
String
GrantedAuthority
AuthenticationProvider
SimpleGrantedAuthority
Authentication
调用前处理
Spring Security 提供了拦截器,这些拦截器控制对安全对象(例如方法调用或 Web 请求)的访问。
关于是否允许继续调用的调用前决定由 .AccessDecisionManager
The AuthorizationManager
AuthorizationManager
取代 AccessDecisionManager
和 AccessDecisionVoter
。
自定义或建议更改为使用 AuthorizationManager
的应用程序。AccessDecisionManager
AccessDecisionVoter
AuthorizationManager
由 AuthorizationFilter
调用,并负责做出最终的访问控制决策。
该接口包含两种方法:AuthorizationManager
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
throws AccessDeniedException {
// ...
}
的方法 将传递它需要的所有相关信息,以便做出授权决策。
特别是,传递 secure 可以检查实际 secure 对象调用中包含的那些参数。
例如,假设安全对象是一个 .
查询 the 以查找任何参数都很容易,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。
如果授予访问权限,则实现应返回正值,如果拒绝访问,则返回负值,并在放弃决策时返回 null。AuthorizationManager
check
Object
MethodInvocation
MethodInvocation
Customer
AuthorizationManager
AuthorizationDecision
AuthorizationDecision
AuthorizationDecision
verify
调用,随后在否定的情况下抛出 an。check
AccessDeniedException
AuthorizationDecision
基于委托的 AuthorizationManager 实现
虽然用户可以实现自己的 delegating 来控制授权的所有方面,但 Spring Security 附带了一个可以与单个 协作的委托。AuthorizationManager
AuthorizationManager
AuthorizationManager
RequestMatcherDelegatingAuthorizationManager
将请求与最合适的委托 匹配。
为了方法安全性,您可以使用 和 。AuthorizationManager
AuthorizationManagerBeforeMethodInterceptor
AuthorizationManagerAfterMethodInterceptor
授权管理器实现说明了相关的类。
使用此方法,可以在授权决策时轮询实施组合。AuthorizationManager
权限授权管理器
Spring Security 提供的最常见是 。
它配置了一组给定的权限,以在当前 .
如果 包含任何已配置的 authority,它将返回 positive。
否则,它将返回负数。AuthorizationManager
AuthorityAuthorizationManager
Authentication
AuthorizationDecision
Authentication
AuthorizationDecision
已验证的授权管理器
另一个管理器是 .
它可用于区分匿名用户、完全身份验证用户和经过记住我身份验证的用户。
许多站点允许在 remember-me 身份验证下进行某些受限访问,但需要用户通过登录来确认其身份才能获得完全访问权限。AuthenticatedAuthorizationManager
自定义授权管理器
显然,您还可以实现自定义,并且可以在其中放置几乎任何您想要的访问控制逻辑。
它可能特定于您的应用程序 (与业务逻辑相关),或者它可能实现一些安全管理逻辑。
例如,您可以创建可以查询 Open Policy Agent 或您自己的授权数据库的实现。AuthorizationManager
您可以在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版实时拒绝帐户被暂停的用户的访问。
您可以通过改为实施来实现相同的结果。AccessDecisionVoter AuthorizationManager |
调整 AccessDecisionManager 和 AccessDecisionVoters
在 之前,Spring Security 发布了 AccessDecisionManager
和 AccessDecisionVoter
。AuthorizationManager
在某些情况下,例如迁移较旧的应用程序,可能需要引入调用 或 的 an 。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
或者只调用 an ,你可以这样做: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
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
的方法 将传递它需要的所有相关信息,以便做出授权决策。
特别是,传递 secure 可以检查实际 secure 对象调用中包含的那些参数。
例如,假设安全对象是一个 .
查询 the 以查找任何参数都很容易,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。
实现应引发 if 访问被拒绝。AccessDecisionManager
decide
Object
MethodInvocation
MethodInvocation
Customer
AccessDecisionManager
AccessDeniedException
该方法由在启动时调用,以确定是否可以处理传递的 .
该方法由安全侦听器实现调用,以确保配置的支持安全侦听器将呈现的安全对象的类型。supports(ConfigAttribute)
AbstractSecurityInterceptor
AccessDecisionManager
ConfigAttribute
supports(Class)
AccessDecisionManager
基于投票的 AccessDecisionManager 实现
虽然用户可以实现自己的实现来控制授权的所有方面,但 Spring Security 包括几个基于投票的实现。Voting Decision Manager 说明了相关的类。AccessDecisionManager
AccessDecisionManager
使用此方法,将对授权决策进行一系列实施轮询。
然后,它根据其对选票的评估来决定是否投掷一个。AccessDecisionVoter
AccessDecisionManager
AccessDeniedException
该接口有三种方法:AccessDecisionVoter
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
具体实现返回 , 可能的值反映在 static fields 和 .
如果投票实现对授权决策没有意见,则它将返回。
如果它确实有观点,则必须返回 或 。int
AccessDecisionVoter
ACCESS_ABSTAIN
ACCESS_DENIED
ACCESS_GRANTED
ACCESS_ABSTAIN
ACCESS_DENIED
ACCESS_GRANTED
Spring Security 提供了三个具体的 s 来统计选票。
该实施将根据非弃权票的共识授予或拒绝访问权限。
提供属性以控制在票数相等或所有投票都弃权的情况下的行为。
如果收到一个或多个投票,则实现将授予访问权限(即,如果至少有一个授权投票,则将忽略拒绝投票)。
与实现一样,有一个参数控制所有选民弃权时的行为。
提供商希望获得一致投票才能授予访问权限,而忽略弃权票。
如果有投票,它将拒绝访问。
与其他实现一样,有一个参数控制所有选民弃权时的行为。AccessDecisionManager
ConsensusBased
AffirmativeBased
ACCESS_GRANTED
ConsensusBased
UnanimousBased
ACCESS_GRANTED
ACCESS_DENIED
可以实施以不同方式统计选票的自定义。
例如,来自特定选民的投票可能会获得额外的权重,而来自特定选民的拒绝投票可能具有否决权。AccessDecisionManager
AccessDecisionVoter
角色投票者
Spring Security 提供的最常用的是 simple ,它将配置属性视为简单的角色名称,如果已为用户分配了该角色,则投票授予访问权限。AccessDecisionVoter
RoleVoter
如果有以前缀 .
如果存在一个,它将投票授予访问权限,它返回一个表示形式(通过方法),正好等于一个或多个以 prefix 开头的 .
如果没有以 开头的 完全匹配项,则将投票拒绝访问。
如果 no 开头为 ,则投票者将弃权。ConfigAttribute
ROLE_
GrantedAuthority
String
getAuthority()
ConfigAttributes
ROLE_
ConfigAttribute
ROLE_
RoleVoter
ConfigAttribute
ROLE_
已验证的选民
我们隐含地看到的另一个投票者是 ,它可以用来区分匿名、完全验证和记住我验证的用户。
许多站点允许在 remember-me 身份验证下进行某些受限访问,但需要用户通过登录来确认其身份才能获得完全访问权限。AuthenticatedVoter
当我们使用该属性授予匿名访问权限时,此属性由 .
有关更多信息,请参阅此类的 Javadoc。IS_AUTHENTICATED_ANONYMOUSLY
AuthenticatedVoter
自定义选民
显然,您还可以实现自定义,并且可以在其中放置几乎任何您想要的访问控制逻辑。
它可能特定于您的应用程序 (与业务逻辑相关),或者它可能实现一些安全管理逻辑。
例如,您可以在 Spring Web 站点上找到一篇博客文章,该文章描述了如何使用投票者实时拒绝帐户被暂停的用户的访问。AccessDecisionVoter
与 Spring Security 的许多其他部分一样,有一个具体的实现,它轮询 s 的列表。
每个 API 都可以修改 return 对象或抛出 .
事实上,多个提供程序可以修改对象,因为前一个提供程序的结果会传递给列表中的下一个提供程序。AfterInvocationManager
AfterInvocationProviderManager
AfterInvocationProvider
AfterInvocationProvider
AccessDeniedException
请注意,如果您使用的是 ,您仍然需要允许 允许 操作的配置属性。
如果您使用的是典型的 Spring Security 包含的实现,则没有为特定的安全方法调用定义配置属性将导致每个实现都放弃投票。
反过来,如果属性 “allowIfAllAbstainDecisions” 为 ,则会引发 an。
您可以通过 (i) 将“allowIfAllAbstainDecisions”设置为(尽管通常不建议这样做)或 (ii) 简单地确保至少有一个配置属性可供投票授予访问权限来避免此潜在问题。
后一种(推荐)方法通常是通过 or 配置属性实现的。AfterInvocationManager
MethodSecurityInterceptor
AccessDecisionManager
AccessDecisionManager
AccessDecisionVoter
AccessDecisionManager
false
AccessDeniedException
true
AccessDecisionVoter
ROLE_USER
ROLE_AUTHENTICATED