此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Security 6.4.1! |
授权架构
本节描述了适用于授权的 Spring Security 体系结构。
当局
Authentication
讨论了所有 implementations 如何存储对象列表。
这些权限表示已授予委托人的权限。
对象由 插入到对象中,稍后在做出授权决策时由实例读取。Authentication
GrantedAuthority
GrantedAuthority
Authentication
AuthenticationManager
AccessDecisionManager
该接口只有一个方法:GrantedAuthority
String getAuthority();
实例使用此方法来获取 .
通过将表示形式返回为 a ,大多数实现都可以轻松 “读取” a。
如果 a 不能精确表示为 a ,则认为 为 “复杂” ,必须返回 。AuthorizationManager
String
GrantedAuthority
String
GrantedAuthority
AuthorizationManager
GrantedAuthority
String
GrantedAuthority
getAuthority()
null
复杂体的一个示例是存储适用于不同客户账号的操作和权限阈值列表的实施。
将这个复合体表示为 a 将非常困难。因此,该方法应返回 .
这向任何人表明它需要支持特定的实现才能理解其内容。GrantedAuthority
GrantedAuthority
String
getAuthority()
null
AuthorizationManager
GrantedAuthority
Spring Security 包括一个具体的实现:.
此实现允许将任何用户指定的 .
安全架构中包含的所有实例都用于填充对象。GrantedAuthority
SimpleGrantedAuthority
String
GrantedAuthority
AuthenticationProvider
SimpleGrantedAuthority
Authentication
您可以使用 进行自定义。 存在以允许自定义用于基于角色的授权规则的前缀。GrantedAuthorityDefaults
GrantedAuthorityDefaults
您可以通过公开 bean 来配置授权规则以使用不同的前缀,如下所示:GrantedAuthorityDefaults
-
Java
-
Kotlin
-
Xml
@Bean
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("MYPREFIX_");
}
companion object {
@Bean
fun grantedAuthorityDefaults() : GrantedAuthorityDefaults {
return GrantedAuthorityDefaults("MYPREFIX_");
}
}
<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
<constructor-arg value="MYPREFIX_"/>
</bean>
你使用方法进行公开,以确保 Spring 在初始化 Spring Security 的方法安全类之前发布它 |
调用处理
Spring Security 提供了拦截器,用于控制对安全对象的访问,例如方法调用或 Web 请求。
是否允许继续调用的调用前决定由实例做出。
此外,调用后是否返回给定值的决定由 instances 做出。AuthorizationManager
AuthorizationManager
The AuthorizationManager
AuthorizationManager
取代 AccessDecisionManager
和 AccessDecisionVoter
。
自定义或建议更改为使用 AuthorizationManager
的应用程序。AccessDecisionManager
AccessDecisionVoter
AuthorizationManager
由 Spring Security 的基于请求、基于方法和基于消息的授权组件调用,并负责做出最终的访问控制决策。
该接口包含两种方法:AuthorizationManager
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
default void 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
授权管理器
AuthorizationManagers
中还有有用的静态工厂,用于将单个 s 组合成更复杂的表达式。AuthorizationManager
自定义授权管理器
显然,您还可以实现自定义,并且可以在其中放置几乎任何您想要的访问控制逻辑。
它可能特定于您的应用程序 (与业务逻辑相关),或者它可能实现一些安全管理逻辑。
例如,您可以创建可以查询 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<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
或者只调用 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<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
分层角色
一个常见的要求是,应用程序中的特定角色应该自动 “包含” 其他角色。 例如,在具有 “admin” 和 “user” 角色概念的应用程序中,您可能希望 admin 能够执行普通用户可以执行的所有操作。 为此,您可以确保所有管理员用户也都分配了 “user” 角色。 或者,您可以修改每个访问约束,这要求 “user” 角色也包括 “admin” 角色。 如果您的应用程序中有很多不同的角色,这可能会变得相当复杂。
使用 role-hierarchy 允许您配置哪些角色(或权限)应包含其他角色。
通过前 POST 注释、 和 JSR-250 注释的基于过滤器的授权和基于方法的授权都支持此功能。
您可以通过以下方式同时为所有这些应用程序配置行为:HttpSecurity#authorizeHttpRequests
DefaultMethodSecurityExpressionHandler
SecuredAuthorizationManager
@Secured
Jsr250AuthorizationManager
-
Java
-
Xml
@Bean
static RoleHierarchy roleHierarchy() {
return RoleHierarchyImpl.withDefaultRolePrefix()
.role("ADMIN").implies("STAFF")
.role("STAFF").implies("USER")
.role("USER").implies("GUEST")
.build();
}
// and, if using pre-post method security also add
@Bean
static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setRoleHierarchy(roleHierarchy);
return expressionHandler;
}
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl" factory-method="fromHierarchy">
<constructor-arg>
<value>
ROLE_ADMIN > ROLE_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST
</value>
</constructor-arg>
</bean>
<!-- and, if using method security also add -->
<bean id="methodSecurityExpressionHandler"
class="org.springframework.security.access.expression.method.MethodSecurityExpressionHandler">
<property ref="roleHierarchy"/>
</bean>
在这里,我们在层次结构中有四个角色。
使用 进行身份验证的用户在根据任何基于过滤器或方法的规则评估安全约束时,其行为将像具有所有四个角色一样。ROLE_ADMIN ⇒ ROLE_STAFF ⇒ ROLE_USER ⇒ ROLE_GUEST
ROLE_ADMIN
该符号可以被认为是“包含”的意思。> |
角色层次结构提供了一种简便的方法,可以简化应用程序的访问控制配置数据和/或减少需要分配给用户的权限数量。 对于更复杂的要求,您可能希望在应用程序所需的特定访问权限和分配给用户的角色之间定义一个逻辑映射,并在加载用户信息时在两者之间进行转换。
旧版授权组件
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 对象调用中包含的那些参数。
例如,假设安全对象是 .
您可以查询 for any 参数,然后在 中实现某种安全逻辑,以确保允许委托人对该客户进行操作。
实现应引发 if 访问被拒绝。decide
AccessDecisionManager
Object
MethodInvocation
MethodInvocation
Customer
AccessDecisionManager
AccessDeniedException
该方法由在启动时调用,以确定是否可以处理传递的 .
该方法由安全侦听器实现调用,以确保配置的支持安全侦听器提供的安全对象的类型。supports(ConfigAttribute)
AbstractSecurityInterceptor
AccessDecisionManager
ConfigAttribute
supports(Class)
AccessDecisionManager
基于投票的 AccessDecisionManager 实现
虽然用户可以实现自己的实现来控制授权的所有方面,但 Spring Security 包括几个基于投票的实现。Voting Decision Manager 描述了相关的类。AccessDecisionManager
AccessDecisionManager
下图显示了界面: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
Spring Security 提供了三种具体的实现来统计选票。
该实现根据非弃权票的共识授予或拒绝访问权限。
提供属性以控制在票数相等或所有投票都弃权的情况下的行为。
如果收到一个或多个投票,则实现将授予访问权限(换句话说,如果至少有一个授权投票,则将忽略拒绝投票)。
与实现一样,有一个参数控制所有选民弃权时的行为。
提供商希望获得一致投票才能授予访问权限,而忽略弃权票。
如果有任何投票,它就会拒绝访问。
与其他实现一样,有一个参数控制所有选民弃权时的行为。AccessDecisionManager
ConsensusBased
AffirmativeBased
ACCESS_GRANTED
ConsensusBased
UnanimousBased
ACCESS_GRANTED
ACCESS_DENIED
您可以实施以不同方式计算选票的自定义。
例如,来自特定选民的投票可能会获得额外的权重,而来自特定选民的拒绝投票可能具有否决权。AccessDecisionManager
AccessDecisionVoter
角色投票者
Spring Security 提供的最常用的是 ,它将配置属性视为角色名称,如果已为用户分配了该角色,则投票授予访问权限。AccessDecisionVoter
RoleVoter
如果 any 以前缀开头,则进行投票。
如果存在 a 返回的表示形式(来自方法)正好等于一个或多个以前缀开头的表示形式,则它会投票授予访问权限。
如果没有任何以 开头的 的完全匹配项,则投票拒绝访问。
如果 no 开头为 ,则选民弃权。ConfigAttribute
ROLE_
GrantedAuthority
String
getAuthority()
ConfigAttributes
ROLE_
ConfigAttribute
ROLE_
RoleVoter
ConfigAttribute
ROLE_
已验证的选民
我们隐式看到的另一个投票者是 ,它可以用来区分匿名用户、完全验证的用户和经过验证的记住我的用户。
许多站点允许在 remember-me 身份验证下进行某些受限访问,但需要用户通过登录来确认其身份才能获得完全访问权限。AuthenticatedVoter
当我们使用该属性授予匿名访问权限时,此属性由 .
有关更多信息,请参阅 AuthenticatedVoter
。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