对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

对于最新的稳定版本,请使用 Spring Security 6.3.1Spring中文文档

本节介绍适用于授权的 Spring Security 体系结构。Spring中文文档

当局

身份验证讨论所有实现如何存储对象列表。 这些代表已授予委托人的权力。 对象由 实例插入到对象中,稍后由实例在做出授权决策时读取。AuthenticationGrantedAuthorityGrantedAuthorityAuthenticationAuthenticationManagerAccessDecisionManagerSpring中文文档

该接口只有一个方法:GrantedAuthoritySpring中文文档

String getAuthority();

实例使用此方法获取 的精确表示。 通过将表示形式返回为 ,a 可以很容易地被大多数实现“读取”。 如果 a 不能精确地表示为 ,则认为 是“复数”,必须返回 。AuthorizationManagerStringGrantedAuthorityStringGrantedAuthorityAuthorizationManagerGrantedAuthorityStringGrantedAuthoritygetAuthority()nullSpring中文文档

复杂的一个示例是存储适用于不同客户帐号的操作和权限阈值列表的实现。 将这种复合体表示为一个将非常困难。因此,该方法应返回 。 这向任何人表明,它需要支持特定的实现才能理解其内容。GrantedAuthorityGrantedAuthorityStringgetAuthority()nullAuthorizationManagerGrantedAuthoritySpring中文文档

Spring Security 包括一个具体的实现:. 此实现允许将任何用户指定的转换为 . 安全体系结构中包含的所有实例都用于填充对象。GrantedAuthoritySimpleGrantedAuthorityStringGrantedAuthorityAuthenticationProviderSimpleGrantedAuthorityAuthenticationSpring中文文档

默认情况下,基于角色的授权规则作为前缀包含在内。 这意味着,如果存在要求安全上下文具有“USER”角色的授权规则,则 Spring Security 将默认查找返回“ROLE_USER”的授权规则。ROLE_GrantedAuthority#getAuthoritySpring中文文档

您可以使用 自定义此设置。 存在以允许自定义用于基于角色的授权规则的前缀。GrantedAuthorityDefaultsGrantedAuthorityDefaultsSpring中文文档

您可以通过公开 Bean 来配置授权规则以使用不同的前缀,如下所示:GrantedAuthorityDefaultsSpring中文文档

自定义 MethodSecurityExpressionHandler
@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 的方法安全类之前发布它GrantedAuthorityDefaultsstatic@ConfigurationSpring中文文档

您可以使用一个方法来公开,以确保 Spring 在初始化 Spring Security 的方法安全类之前发布它GrantedAuthorityDefaultsstatic@ConfigurationSpring中文文档

调用处理

Spring Security 提供了控制对安全对象(例如方法调用或 Web 请求)的访问的拦截器。 关于是否允许继续调用的调用前决定由实例做出。 此外,关于是否可以返回给定值的调用后决定由实例做出。AuthorizationManagerAuthorizationManagerSpring中文文档

The AuthorizationManager

自定义或鼓励更改为使用 AuthorizationManager 的应用程序。AccessDecisionManagerAccessDecisionVoterSpring中文文档

AuthorizationManager由 Spring Security 的基于请求基于方法基于消息的授权组件调用,并负责做出最终的访问控制决策。 该接口包含两种方法:AuthorizationManagerSpring中文文档

AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);

default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
        throws AccessDeniedException {
    // ...
}

的方法传递了它需要的所有相关信息,以便做出授权决定。 具体而言,传递 secure 可以检查实际安全对象调用中包含的参数。 例如,假设安全对象是 . 查询任何参数都很容易,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。 如果授予访问权限,则实现应返回正数,如果访问被拒绝,则返回负数,在放弃做出决定时返回空值。AuthorizationManagercheckObjectMethodInvocationMethodInvocationCustomerAuthorizationManagerAuthorizationDecisionAuthorizationDecisionAuthorizationDecisionSpring中文文档

verify调用,然后在负数的情况下抛出 an 。checkAccessDeniedExceptionAuthorizationDecisionSpring中文文档

基于委托的 AuthorizationManager 实现

虽然用户可以实现自己的授权来控制授权的所有方面,但 Spring Security 附带了一个可以与个人协作的委托。AuthorizationManagerAuthorizationManagerAuthorizationManagerSpring中文文档

RequestMatcherDelegatingAuthorizationManager将请求与最合适的委托进行匹配。 为了方法安全,可以使用 和 .AuthorizationManagerAuthorizationManagerBeforeMethodInterceptorAuthorizationManagerAfterMethodInterceptorSpring中文文档

授权层次结构
图 1.授权管理器实现

使用这种方法,可以对授权决策的实现组合进行轮询。AuthorizationManagerSpring中文文档

AuthorityAuthorizationManager

Spring Security 中最常见的是 。 它配置了一组给定的权限,以在当前 . 如果包含任何配置的权限,它将返回正值。 否则它将返回否定数。AuthorizationManagerAuthorityAuthorizationManagerAuthenticationAuthorizationDecisionAuthenticationAuthorizationDecisionSpring中文文档

AuthenticatedAuthorizationManager

另一位经理是 . 它可用于区分匿名用户、完全身份验证用户和记住我身份验证的用户。 许多网站允许在“记住我”身份验证下进行某些有限的访问,但要求用户通过登录来确认其身份才能进行完全访问。AuthenticatedAuthorizationManagerSpring中文文档

授权管理器

还有一些有用的静态工厂,用于将单个 s 组合成更复杂的表达式。AuthenticationManagersAuthenticationManagerSpring中文文档

自定义授权管理器

显然,您还可以实现自定义,并且可以在其中放置几乎任何所需的访问控制逻辑。 它可能特定于您的应用程序(与业务逻辑相关),也可能实现某些安全管理逻辑。 例如,您可以创建一个可以查询 Open Policy Agent 或您自己的授权数据库的实现。AuthorizationManagerSpring中文文档

您将在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版实时拒绝帐户已被暂停的用户的访问。 您可以通过实施来实现相同的结果。AccessDecisionVoterAuthorizationManager
您将在 Spring 网站上找到一篇博客文章,其中描述了如何使用旧版实时拒绝帐户已被暂停的用户的访问。 您可以通过实施来实现相同的结果。AccessDecisionVoterAuthorizationManager

调整 AccessDecisionManager 和 AccessDecisionVoters

在此之前,Spring Security 发布了 AccessDecisionManagerAccessDecisionVoterAuthorizationManagerSpring中文文档

在某些情况下,例如迁移较旧的应用程序,可能需要引入调用 或 的 .AuthorizationManagerAccessDecisionManagerAccessDecisionVoterSpring中文文档

要调用现有的 ,您可以执行以下操作:AccessDecisionManagerSpring中文文档

适配 AccessDecisionManager
@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);
    }
}

然后将其连接到您的 .SecurityFilterChainSpring中文文档

或者只调用一个,可以做:AccessDecisionVoterSpring中文文档

调整 AccessDecisionVoter
@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;
    }
}

然后将其连接到您的 .SecurityFilterChainSpring中文文档

分层角色

应用程序中的特定角色应自动“包含”其他角色,这是一项常见要求。 例如,在具有“管理员”和“用户”角色概念的应用程序中,您可能希望管理员能够执行普通用户可以执行的所有操作。 为此,您可以确保还为所有管理员用户分配了“用户”角色。 或者,您可以修改每个需要“用户”角色的访问约束,以包括“管理员”角色。 如果您在应用程序中有很多不同的角色,这可能会变得非常复杂。Spring中文文档

使用角色层次结构可以配置哪些角色(或权限)应包括其他角色。 Spring Security 的 , 的扩展版本配置了 ,它从中获取分配给用户的所有“可访问权限”。 典型配置可能如下所示:RoleVoterRoleHierarchyVoterRoleHierarchySpring中文文档

分层角色配置
@Bean
static RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
            "ROLE_STAFF > ROLE_USER\n" +
            "ROLE_USER > ROLE_GUEST");
    return hierarchy;
}

// and, if using 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">
	<property name="hierarchy">
		<value>
			ROLE_ADMIN > ROLE_STAFF
			ROLE_STAFF > ROLE_USER
			ROLE_USER > ROLE_GUEST
		</value>
	</property>
</bean>

<!-- and, if using method security also add -->
<bean id="methodSecurityExpressionHandler"
        class="org.springframework.security.access.expression.method.MethodSecurityExpressionHandler">
    <property ref="roleHierarchy"/>
</bean>
RoleHierarchyBean 配置尚未移植到 。 因此,此示例使用 . 如果您需要方法安全性的支持,请继续使用,直到 github.com/spring-projects/spring-security/issues/12783 完成。@EnableMethodSecurityAccessDecisionVoterRoleHierarchy@EnableGlobalMethodSecurity

在这里,我们在层次结构中有四个角色。 使用 进行身份验证的用户在根据适合调用上述内容评估安全约束时,将表现得好像他们具有所有四个角色。 该符号可以被认为是“包括”的意思。ROLE_ADMIN ⇒ ROLE_STAFF ⇒ ROLE_USER ⇒ ROLE_GUESTROLE_ADMINAuthorizationManagerRoleHierarchyVoter>Spring中文文档

角色层次结构提供了一种方便的方法,可以简化应用程序的访问控制配置数据和/或减少需要分配给用户的权限数量。 对于更复杂的要求,您可能希望在应用程序所需的特定访问权限和分配给用户的角色之间定义逻辑映射,并在加载用户信息时在两者之间转换。Spring中文文档

RoleHierarchyBean 配置尚未移植到 。 因此,此示例使用 . 如果您需要方法安全性的支持,请继续使用,直到 github.com/spring-projects/spring-security/issues/12783 完成。@EnableMethodSecurityAccessDecisionVoterRoleHierarchy@EnableGlobalMethodSecurity

旧授权组件

Spring Security 包含一些旧组件。 由于它们尚未被删除,因此出于历史目的,包括文档。 他们推荐的替代品如上所述。

The AccessDecisionManager

由 和 负责做出最终访问控制决策。 该接口包含三种方法:AccessDecisionManagerAbstractSecurityInterceptorAccessDecisionManagerSpring中文文档

void decide(Authentication authentication, Object secureObject,
	Collection<ConfigAttribute> attrs) throws AccessDeniedException;

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

该方法传递了做出授权决策所需的所有相关信息。 具体而言,传递 secure 可以检查实际安全对象调用中包含的参数。 例如,假设安全对象是 . 您可以查询任何参数,然后在 中实现某种安全逻辑,以确保允许主体对该客户进行操作。 如果访问被拒绝,则实现应抛出一个。decideAccessDecisionManagerObjectMethodInvocationMethodInvocationCustomerAccessDecisionManagerAccessDeniedExceptionSpring中文文档

该方法由 at 启动时调用,以确定是否可以处理传递的 . 该方法由安全拦截器实现调用,以确保配置支持安全拦截器提供的安全对象类型。supports(ConfigAttribute)AbstractSecurityInterceptorAccessDecisionManagerConfigAttributesupports(Class)AccessDecisionManagerSpring中文文档

基于投票的 AccessDecisionManager 实现

虽然用户可以实现自己的实现来控制授权的所有方面,但 Spring Security 包含多个基于投票的实现。投票决策管理器描述了相关的类。AccessDecisionManagerAccessDecisionManagerSpring中文文档

下图显示了界面:AccessDecisionManagerSpring中文文档

访问决策投票
图2.投票决策管理器

通过使用这种方法,将对授权决策轮询一系列实现。 然后根据其对选票的评估来决定是否投掷。AccessDecisionVoterAccessDecisionManagerAccessDeniedExceptionSpring中文文档

该接口有三种方法:AccessDecisionVoterSpring中文文档

int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);

boolean supports(ConfigAttribute attribute);

boolean supports(Class clazz);

具体实现返回 ,可能的值反映在名为 和 的静态字段中。 如果投票实现对授权决定没有意见,则返回。 如果它确实有意见,它必须返回 或 。intAccessDecisionVoterACCESS_ABSTAINACCESS_DENIEDACCESS_GRANTEDACCESS_ABSTAINACCESS_DENIEDACCESS_GRANTEDSpring中文文档

Spring Security 提供了三个具体的实现来统计投票。 实施根据非弃权票的共识授予或拒绝访问。 提供属性以控制在票数相等或所有票均弃权时的行为。 如果收到一票或多票,则实现授予访问权限(换句话说,如果至少有一票授予票,则否决票将被忽略)。 与实现一样,如果所有投票者都弃权,则有一个参数可以控制行为。 提供商希望获得一致投票以授予访问权限,而忽略弃权票。 如果有任何投票,它拒绝访问。 与其他实现一样,如果所有投票者都弃权,则有一个参数可以控制行为。AccessDecisionManagerConsensusBasedAffirmativeBasedACCESS_GRANTEDConsensusBasedUnanimousBasedACCESS_GRANTEDACCESS_DENIEDSpring中文文档

您可以实现以不同方式统计选票的自定义。 例如,来自特定选民的选票可能会获得额外的权重,而来自特定选民的反对票可能会产生否决权。AccessDecisionManagerAccessDecisionVoterSpring中文文档

角色选民

Spring Security 提供的最常用的是 ,它将配置属性视为角色名称,并在用户被分配了该角色时投票授予访问权限。AccessDecisionVoterRoleVoterSpring中文文档

如果有的话,它会投票以前缀开头。 如果有一个返回的表示(来自方法)正好等于一个或多个以前缀开头的表示,则它投票授予访问权限。 如果任何以 开头的 没有完全匹配,则投票拒绝访问。 如果以 开头,则投票者弃权。ConfigAttributeROLE_GrantedAuthorityStringgetAuthority()ConfigAttributesROLE_ConfigAttributeROLE_RoleVoterConfigAttributeROLE_Spring中文文档

AuthenticatedVoter

我们隐式看到的另一个投票者是 ,它可用于区分匿名、完全身份验证和记住我身份验证的用户。 许多网站允许在“记住我”身份验证下进行某些有限访问,但要求用户通过登录来确认其身份才能进行完全访问。AuthenticatedVoterSpring中文文档

当我们使用该属性授予匿名访问权限时,此属性正在由 . 有关详细信息,请参阅 AuthenticatedVoterIS_AUTHENTICATED_ANONYMOUSLYAuthenticatedVoterSpring中文文档

自定义投票者

您还可以实现自定义,并在其中放置几乎任何所需的访问控制逻辑。 它可能特定于您的应用程序(与业务逻辑相关),也可能实现某些安全管理逻辑。 例如,在 Spring 网站上,您可以找到一篇博客文章,该文章描述了如何使用投票者实时拒绝其帐户已被暂停的用户的访问。AccessDecisionVoterSpring中文文档

调用后
图3.调用实现后

与 Spring Security 的许多其他部分一样,它有一个具体的实现,它轮询 s 列表。 允许每个对象修改返回对象或抛出 . 实际上,多个提供程序可以修改对象,因为前一个提供程序的结果将传递给列表中的下一个提供程序。AfterInvocationManagerAfterInvocationProviderManagerAfterInvocationProviderAfterInvocationProviderAccessDeniedExceptionSpring中文文档

请注意,如果您使用的是 ,您仍然需要允许 的配置属性来允许操作。 如果您使用的是典型的 Spring Security 包含的实现,那么没有为特定安全方法调用定义配置属性将导致每个实现投弃权票。 反过来,如果属性“allowIfAllAbstainDecisions”为 ,则将抛出 an。 您可以通过以下两种方式避免此潜在问题:(i) 将“allowIfAllAbstainDecisions”设置为(尽管通常不建议这样做)或 (ii) 仅确保至少有一个配置属性将投票授予访问权限。 后一种(推荐的)方法通常是通过 or 配置属性实现的。AfterInvocationManagerMethodSecurityInterceptorAccessDecisionManagerAccessDecisionManagerAccessDecisionVoterAccessDecisionManagerfalseAccessDeniedExceptiontrueAccessDecisionVoterROLE_USERROLE_AUTHENTICATEDSpring中文文档

Spring Security 包含一些旧组件。 由于它们尚未被删除,因此出于历史目的,包括文档。 他们推荐的替代品如上所述。