|
对于最新的稳定版本,请使用 Spring Security 6.5.3! |
授权架构
当局
Authentication,讨论了所有Authentication实现存储一个列表GrantedAuthority对象。
这些代表已授予委托人的权限。
这GrantedAuthority对象入到Authentication对象AuthenticationManager稍后由AuthorizationManager在做出授权决策时。
GrantedAuthority是一个只有一种方法的接口:
String getAuthority();
这种方法允许AuthorizationManagers 以获得精确的String的表示GrantedAuthority.
通过将表示形式返回为String一个GrantedAuthority大多数人都能轻松“阅读”AuthorizationManagers 和AccessDecisionManagers.
如果GrantedAuthority不能精确地表示为String这GrantedAuthority被认为是“复杂”的,并且getAuthority()必须返回null.
“复合体”的例子GrantedAuthority将是一个实现,用于存储适用于不同客户帐号的作和权限阈值列表。
代表这个综合体GrantedAuthority作为String这将是相当困难的,因此getAuthority()方法应返回null.
这将向任何AuthorizationManager它需要专门支持GrantedAuthority实现以理解其内容。
Spring Security 包括一个混凝土GrantedAuthority实现SimpleGrantedAuthority.
这允许任何用户指定的String转换为GrantedAuthority.
都AuthenticationProvider安全架构中包含的SimpleGrantedAuthority以填充Authentication对象。
调用前处理
Spring Security提供了控制对安全对象(例如方法调用或Web请求)的访问的拦截器。
关于是否允许调用继续进行的调用前决定由AccessDecisionManager.
授权管理器
AuthorizationManager取代两者AccessDecisionManager和AccessDecisionVoter.
自定义AccessDecisionManager或AccessDecisionVoter鼓励更改为AuthorizationManager.
AuthorizationManagers 由AuthorizationFilter并负责做出最终的访问控制决策。
这AuthorizationManager接口包含两个方法:
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
throws AccessDeniedException {
// ...
}
这AuthorizationManager的check方法会传递它所需的所有相关信息,以便做出授权决策。
特别是,通过安全的Object允许检查实际安全对象调用中包含的那些参数。
例如,假设安全对象是MethodInvocation.
查询MethodInvocation对于任何Customer参数,然后在AuthorizationManager以确保允许委托人对该客户进行作。
预计实现将返回积极的AuthorizationDecision如果授予访问权限,则为否定AuthorizationDecision如果访问被拒绝,并且AuthorizationDecision当放弃做出决定时。
verify调用check并随后抛出一个AccessDeniedException在负的情况下AuthorizationDecision.
基于委托的 AuthorizationManager 实现
虽然用户可以实现自己的AuthorizationManager为了控制授权的各个方面,Spring Security 附带了一个委托AuthorizationManager可以与个人协作AuthorizationManagers.
RequestMatcherDelegatingAuthorizationManager将请求与最合适的委托进行匹配AuthorizationManager.
为了方法安全性,您可以使用AuthorizationManagerBeforeMethodInterceptor和AuthorizationManagerAfterMethodInterceptor.
授权管理器实现说明了相关类。
使用这种方法,组合AuthorizationManager可以在授权决策上轮询实现。
权限授权管理器
最常见的AuthorizationManager与 Spring Security 一起提供的是AuthorityAuthorizationManager.
它配置了一组给定的权限,以便在当前Authentication.
它将返回正数AuthorizationDecision应该Authentication包含任何已配置的权限。
它将返回一个负数AuthorizationDecision否则。
AuthenticatedAuthorizationManager
另一个管理器是AuthenticatedAuthorizationManager.
它可用于区分匿名用户、完全身份验证用户和记住我身份验证用户。
许多网站允许在记住我身份验证下进行某些有限访问,但要求用户通过登录来确认其身份才能获得完全访问权限。
自定义授权管理器
显然,您还可以实现自定义AuthorizationManager而且你可以将任何你想要的访问控制逻辑放入其中。
它可能特定于您的应用程序(与业务逻辑相关),也可能实现一些安全管理逻辑。
例如,您可以创建一个可以查询 Open Policy Agent 或您自己的授权数据库的实现。
你会在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版AccessDecisionVoter以实时拒绝帐户被暂停的用户访问。
您可以通过实施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<ConfigAttribute> 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<ConfigAttribute> 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<ConfigAttribute> 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.
分层角色
应用程序中的特定角色应自动“包含”其他角色,这是一个常见的要求。 例如,在具有“管理员”和“用户”角色概念的应用程序中,您可能希望管理员能够执行普通用户可以执行的所有作。 为此,您可以确保所有管理员用户也都分配了“用户”角色。 或者,您可以修改每个访问约束,这些限制要求“用户”角色也包括“管理员”角色。 如果您的应用程序中有很多不同的角色,这可能会变得非常复杂。
使用角色层次结构允许您配置哪些角色(或权限)应包括其他角色。
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 包含一些遗留组件。 由于它们尚未被删除,因此出于历史目的而包含文档。 他们推荐的替代品如上所示。 |
AccessDecisionManager 的
这AccessDecisionManager被AbstractSecurityInterceptor并负责做出最终的访问控制决策。
这AccessDecisionManager接口包含三种方法:
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以确保允许委托人对该客户进行作。
实现应抛出AccessDeniedException如果访问被拒绝。
这supports(ConfigAttribute)方法由AbstractSecurityInterceptor在启动时确定AccessDecisionManager可以处理传递的ConfigAttribute.
这supports(Class)方法被安全拦截器实现调用,以确保配置的AccessDecisionManager支持安全拦截器将呈现的安全对象类型。
基于投票的 AccessDecisionManager 实现
虽然用户可以实现自己的AccessDecisionManager为了控制授权的各个方面,Spring Security 包括几个AccessDecisionManager基于投票的实现。投票决策管理器说明了相关类。
使用这种方法,一系列AccessDecisionVoter根据授权决策轮询实现。
这AccessDecisionManager然后决定是否抛出一个AccessDeniedException基于其对选票的评估。
这AccessDecisionVoter接口有三种方法:
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.
有三种具体AccessDecisionManagers 提供了统计选票的 Spring Security。
这ConsensusBased实施将根据非弃权票的共识授予或拒绝访问权限。
提供属性来控制在票数相等或所有票都弃权的情况下的行为。
这AffirmativeBased如果一个或多个ACCESS_GRANTED已收到选票(即,如果至少有一张授权票,则拒绝投票将被忽略)。
像ConsensusBased实施时,如果所有选民都弃权,则有一个参数可以控制行为。
这UnanimousBased提供者期望一致ACCESS_GRANTED投票以授予访问权限,忽略弃权。
如果有任何访问,它将拒绝访问ACCESS_DENIED投票。
与其他实现一样,如果所有选民都弃权,则有一个参数可以控制行为。
可以实现自定义AccessDecisionManager以不同的方式计算投票。例如,来自特定AccessDecisionVoter可能会获得额外的权重,而特定选民的拒绝投票可能会产生否决权。
角色选民
最常用的AccessDecisionVoterSpring Security 提供的简单RoleVoter,它将配置属性视为简单的角色名称,并在为用户分配了该角色时投票授予访问权限。
如果有的话,它将进行投票ConfigAttribute以前缀开头ROLE_. 如果有GrantedAuthority它返回一个String表示(通过getAuthority()方法)恰好等于一个或多个ConfigAttributes以前缀开头ROLE_. 如果没有任何完全匹配的ConfigAttribute开头ROLE_这RoleVoter将投票拒绝访问。如果否ConfigAttribute开头为ROLE_,选民将弃权。
已认证选民
我们隐含地看到的另一个选民是AuthenticatedVoter,可用于区分匿名用户、完全身份验证用户和记住我身份验证用户。许多网站允许在记住我身份验证下进行某些有限访问,但要求用户通过登录来确认其身份才能获得完全访问权限。
当我们使用IS_AUTHENTICATED_ANONYMOUSLY为了授予匿名访问权限,此属性由AuthenticatedVoter.
有关更多信息,请参阅此类的 Javadoc。
自定义选民
显然,您还可以实现自定义AccessDecisionVoter而且你可以将任何你想要的访问控制逻辑放入其中。
它可能特定于您的应用程序(与业务逻辑相关),也可能实现一些安全管理逻辑。
例如,您会在 Spring 网站上找到一篇博客文章,其中描述了如何使用投票者实时拒绝帐户被暂停的用户的访问。
与 Spring Security 的许多其他部分一样,AfterInvocationManager有一个单一的具体实现,AfterInvocationProviderManager,它轮询一个列表AfterInvocationProviders.
每AfterInvocationProvider允许修改返回对象或抛出AccessDeniedException.
事实上,多个提供程序可以修改对象,因为上一个提供程序的结果被传递给列表中的下一个提供程序。
请注意,如果您使用AfterInvocationManager,您仍然需要允许MethodSecurityInterceptor的AccessDecisionManager以允许作。
如果您使用的是典型的 Spring SecurityAccessDecisionManager实现,没有为特定安全方法调用定义配置属性将导致AccessDecisionVoter弃权。
反过来,如果AccessDecisionManager属性“allowIfAllAbstainDecisions”是false一AccessDeniedException将被扔出。
您可以通过 (i) 将“allowIfAllAbstainDecisions”设置为true(尽管通常不建议这样做)或 (ii) 只需确保至少有一个配置属性AccessDecisionVoter将投票授予访问权限。
后一种(推荐的)方法通常通过ROLE_USER或ROLE_AUTHENTICATED配置属性。