本节介绍适用于授权的 Spring Security 体系结构。
当局
身份验证
讨论所有实现如何存储对象列表。
这些代表已授予委托人的权力。
对象由 实例插入到对象中,稍后由实例在做出授权决策时读取。Authentication
GrantedAuthority
GrantedAuthority
Authentication
AuthenticationManager
AccessDecisionManager
该接口只有一个方法:GrantedAuthority
String getAuthority();
实例使用此方法获取 的精确表示。
通过将表示形式返回为 ,a 可以很容易地被大多数实现“读取”。
如果 a 不能精确地表示为 ,则认为 是“复数”,必须返回 。AuthorizationManager
String
GrantedAuthority
String
GrantedAuthority
AuthorizationManager
GrantedAuthority
String
GrantedAuthority
getAuthority()
null
复杂的一个示例是存储适用于不同客户帐号的操作和权限阈值列表的实现。
将这种复合体表示为一个将非常困难。因此,该方法应返回 。
这向任何人表明,它需要支持特定的实现才能理解其内容。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 在初始化 Spring Security 的方法安全类之前发布它 |
调用处理
Spring Security 提供了控制对安全对象(例如方法调用或 Web 请求)的访问的拦截器。
关于是否允许继续调用的调用前决定由实例做出。
此外,关于是否可以返回给定值的调用后决定由实例做出。AuthorizationManager
AuthorizationManager
The AuthorizationManager
AuthorizationManager
取代 AccessDecisionManager
和 AccessDecisionVoter
。
自定义或鼓励更改为使用 AuthorizationManager
的应用程序。AccessDecisionManager
AccessDecisionVoter
AuthorizationManager
由 Spring Security 的基于请求、基于方法和基于消息的授权组件调用,并负责做出最终的访问控制决策。
该接口包含两种方法:AuthorizationManager
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
throws AccessDeniedException {
// ...
}
的方法传递了它需要的所有相关信息,以便做出授权决定。
具体而言,传递 secure 可以检查实际安全对象调用中包含的参数。
例如,假设安全对象是 .
查询任何参数都很容易,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。
如果授予访问权限,则实现应返回正数,如果访问被拒绝,则返回负数,在放弃做出决定时返回空值。AuthorizationManager
check
Object
MethodInvocation
MethodInvocation
Customer
AuthorizationManager
AuthorizationDecision
AuthorizationDecision
AuthorizationDecision
verify
调用,然后在负数的情况下抛出 an 。check
AccessDeniedException
AuthorizationDecision
基于委托的 AuthorizationManager 实现
虽然用户可以实现自己的授权来控制授权的所有方面,但 Spring Security 附带了一个可以与个人协作的委托。AuthorizationManager
AuthorizationManager
AuthorizationManager
RequestMatcherDelegatingAuthorizationManager
将请求与最合适的委托进行匹配。
为了方法安全,可以使用 和 .AuthorizationManager
AuthorizationManagerBeforeMethodInterceptor
AuthorizationManagerAfterMethodInterceptor
使用这种方法,可以对授权决策的实现组合进行轮询。AuthorizationManager
AuthorityAuthorizationManager
Spring Security 中最常见的是 。
它配置了一组给定的权限,以在当前 .
如果包含任何配置的权限,它将返回正值。
否则它将返回否定数。AuthorizationManager
AuthorityAuthorizationManager
Authentication
AuthorizationDecision
Authentication
AuthorizationDecision
AuthenticatedAuthorizationManager
另一位经理是 .
它可用于区分匿名用户、完全身份验证用户和记住我身份验证的用户。
许多网站允许在“记住我”身份验证下进行某些有限的访问,但要求用户通过登录来确认其身份才能进行完全访问。AuthenticatedAuthorizationManager
授权管理器
AuthorizationManagers
中还有一些有用的静态工厂,用于将单个 s 组合成更复杂的表达式。AuthorizationManager
自定义授权管理器
显然,您还可以实现自定义,并且可以在其中放置几乎任何所需的访问控制逻辑。
它可能特定于您的应用程序(与业务逻辑相关),也可能实现某些安全管理逻辑。
例如,您可以创建一个可以查询 Open Policy Agent 或您自己的授权数据库的实现。AuthorizationManager
您将在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版实时拒绝帐户已被暂停的用户的访问。
您可以通过实施来实现相同的结果。AccessDecisionVoter AuthorizationManager |
您将在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版实时拒绝帐户已被暂停的用户的访问。
您可以通过实施来实现相同的结果。AccessDecisionVoter AuthorizationManager |
调整 AccessDecisionManager 和 AccessDecisionVoters
在此之前,Spring Security 发布了 AccessDecisionManager
和 AccessDecisionVoter
。AuthorizationManager
在某些情况下,例如迁移较旧的应用程序,可能需要引入调用 或 的 .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
分层角色
应用程序中的特定角色应自动“包含”其他角色,这是一项常见要求。 例如,在具有“管理员”和“用户”角色概念的应用程序中,您可能希望管理员能够执行普通用户可以执行的所有操作。 为此,您可以确保还为所有管理员用户分配了“用户”角色。 或者,您可以修改每个需要“用户”角色的访问约束,以包括“管理员”角色。 如果您在应用程序中有很多不同的角色,这可能会变得非常复杂。
使用角色层次结构可以配置哪些角色(或权限)应包括其他角色。
对于基于过滤器的授权,以及通过前后注释、for 和 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 可以检查实际安全对象调用中包含的参数。
例如,假设安全对象是 .
您可以查询任何参数,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。
如果访问被拒绝,则实现应抛出一个。decide
AccessDecisionManager
Object
MethodInvocation
MethodInvocation
Customer
AccessDecisionManager
AccessDeniedException
该方法由 at 启动时调用,以确定是否可以处理传递的 .
该方法由安全拦截器实现调用,以确保配置支持安全拦截器提供的安全对象类型。supports(ConfigAttribute)
AbstractSecurityInterceptor
AccessDecisionManager
ConfigAttribute
supports(Class)
AccessDecisionManager
基于投票的 AccessDecisionManager 实现
虽然用户可以实现自己的实现来控制授权的所有方面,但 Spring Security 包含多个基于投票的实现。投票决策管理器描述了相关的类。AccessDecisionManager
AccessDecisionManager
下图显示了界面:AccessDecisionManager
![访问决策投票](https://docs.spring.io/spring-security/reference/6.3/_images/servlet/authorization/access-decision-voting.png)
通过使用这种方法,将对授权决策轮询一系列实现。
然后根据其对选票的评估来决定是否投掷。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
如果有的话,它会投票以前缀开头。
如果有一个返回的表示(来自方法)正好等于一个或多个以前缀开头的表示,则它投票授予访问权限。
如果任何以 开头的 没有完全匹配,则投票拒绝访问。
如果以 开头,则投票者弃权。ConfigAttribute
ROLE_
GrantedAuthority
String
getAuthority()
ConfigAttributes
ROLE_
ConfigAttribute
ROLE_
RoleVoter
ConfigAttribute
ROLE_
AuthenticatedVoter
我们隐式看到的另一个投票者是 ,它可用于区分匿名、完全身份验证和记住我身份验证的用户。
许多网站允许在“记住我”身份验证下进行某些有限访问,但要求用户通过登录来确认其身份才能进行完全访问。AuthenticatedVoter
当我们使用该属性授予匿名访问权限时,此属性正在由 .
有关详细信息,请参阅 AuthenticatedVoter
。IS_AUTHENTICATED_ANONYMOUSLY
AuthenticatedVoter
自定义投票者
您还可以实现自定义,并在其中放置几乎任何所需的访问控制逻辑。
它可能特定于您的应用程序(与业务逻辑相关),也可能实现某些安全管理逻辑。
例如,在 Spring 网站上,您可以找到一篇博客文章,该文章描述了如何使用投票者实时拒绝其帐户已被暂停的用户的访问。AccessDecisionVoter
![调用后](https://docs.spring.io/spring-security/reference/6.3/_images/servlet/authorization/after-invocation.png)
与 Spring Security 的许多其他部分一样,它有一个具体的实现,它轮询 s 列表。
允许每个对象修改返回对象或抛出 .
实际上,多个提供程序可以修改对象,因为前一个提供程序的结果将传递给列表中的下一个提供程序。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
Spring Security 包含一些旧组件。 由于它们尚未被删除,因此出于历史目的,包括文档。 他们推荐的替代品如上所述。 |