跳到主要内容

Java 认证与授权服务 (JAAS) 提供者

QWen Max 中英对照 JAAS Java Authentication and Authorization Service (JAAS) Provider

Spring Security 提供了一个包,用于将认证请求委托给 Java 认证和授权服务 (JAAS)。本节将讨论该包。

AbstractJaasAuthenticationProvider

AbstractJaasAuthenticationProvider 类是所提供的 JAAS AuthenticationProvider 实现的基础。子类必须实现一个创建 LoginContext 的方法。AbstractJaasAuthenticationProvider 有许多可以注入的依赖项,本节的其余部分将对此进行讨论。

JAAS CallbackHandler

大多数 JAAS LoginModule 实例都需要某种形式的回调。这些回调通常用于从用户那里获取用户名和密码。

在 Spring Security 部署中,Spring Security 负责这种用户交互(通过认证机制)。因此,在认证请求被委派给 JAAS 时,Spring Security 的认证机制已经完全填充了一个包含 JAAS LoginModule 所需所有信息的 Authentication 对象。

因此,Spring Security 的 JAAS 包提供了两个默认的回调处理器:JaasNameCallbackHandlerJaasPasswordCallbackHandler。这些回调处理器各自实现了 JaasAuthenticationCallbackHandler。在大多数情况下,可以使用这些回调处理器而无需了解其内部机制。

对于那些需要完全控制回调行为的用户,AbstractJaasAuthenticationProvider 内部将这些 JaasAuthenticationCallbackHandler 实例用一个 InternalCallbackHandler 包装起来。InternalCallbackHandler 是实际实现 JAAS 标准 CallbackHandler 接口的类。每当使用 JAAS LoginModule 时,都会传递一个应用程序上下文中配置的 InternalCallbackHandler 实例列表。如果 LoginModule 请求对 InternalCallbackHandler 实例进行回调,则该回调会依次传递给被包装的 JaasAuthenticationCallbackHandler 实例。

JAAS AuthorityGranter

JAAS 与主体(principals)一起工作。甚至“角色”在 JAAS 中也表示为主体。另一方面,Spring Security 则使用 Authentication 对象。每个 Authentication 对象包含一个单独的主体和多个 GrantedAuthority 实例。为了便于在这些不同概念之间进行映射,Spring Security 的 JAAS 包含了一个 AuthorityGranter 接口。

AuthorityGranter 负责检查 JAAS 主体并返回一组表示分配给该主体的权限的 String 对象。对于每个返回的权限字符串,AbstractJaasAuthenticationProvider 会创建一个包含该权限字符串和传递给 AuthorityGranter 的 JAAS 主体的 JaasGrantedAuthority(它实现了 Spring Security 的 GrantedAuthority 接口)。AbstractJaasAuthenticationProvider 通过首先使用 JAAS LoginModule 成功验证用户的凭据,然后访问其返回的 LoginContext 来获取 JAAS 主体。调用 LoginContext.getSubject().getPrincipals(),并将每个结果主体传递给在 AbstractJaasAuthenticationProvider.setAuthorityGranters(List) 属性中定义的每个 AuthorityGranter

Spring Security 没有包含任何生产环境的 AuthorityGranter 实例,因为每个 JAAS 主体都有特定于实现的含义。不过,在单元测试中有一个 TestAuthorityGranter,它展示了一个简单的 AuthorityGranter 实现。

DefaultJaasAuthenticationProvider

DefaultJaasAuthenticationProvider 允许将 JAAS Configuration 对象作为依赖项注入到其中。然后,它通过使用注入的 JAAS Configuration 来创建一个 LoginContext。这意味着 DefaultJaasAuthenticationProvider 不绑定到任何特定的 Configuration 实现,而 JaasAuthenticationProvider 则是绑定的。

InMemoryConfiguration

为了方便将 Configuration 注入到 DefaultJaasAuthenticationProvider 中,提供了一个默认的内存实现,名为 InMemoryConfiguration。该实现的构造函数接受一个 Map,其中每个键表示一个登录配置名称,值表示 AppConfigurationEntry 实例的 ArrayInMemoryConfiguration 还支持一个默认的 AppConfigurationEntry 对象的 Array,如果在提供的 Map 中找不到映射,则使用该默认数组。有关详细信息,请参阅 InMemoryConfiguration 的 Javadoc。

DefaultJaasAuthenticationProvider 示例配置

虽然 InMemoryConfiguration 的 Spring 配置可能比标准的 JAAS 配置文件更为冗长,但是将其与 DefaultJaasAuthenticationProvider 一起使用比 JaasAuthenticationProvider 更加灵活,因为它不依赖于默认的 Configuration 实现。

下一个示例提供了使用 InMemoryConfigurationDefaultJaasAuthenticationProvider 配置。请注意,Configuration 的自定义实现也可以轻松注入到 DefaultJaasAuthenticationProvider 中。

<bean id="jaasAuthProvider"
class="org.springframework.security.authentication.jaas.DefaultJaasAuthenticationProvider">
<property name="configuration">
<bean class="org.springframework.security.authentication.jaas.memory.InMemoryConfiguration">
<constructor-arg>
<map>
<!--
SPRINGSECURITY is the default loginContextName
for AbstractJaasAuthenticationProvider
-->
<entry key="SPRINGSECURITY">
<array>
<bean class="javax.security.auth.login.AppConfigurationEntry">
<constructor-arg value="sample.SampleLoginModule" />
<constructor-arg>
<util:constant static-field=
"javax.security.auth.login.AppConfigurationEntry$LoginModuleControlFlag.REQUIRED"/>
</constructor-arg>
<constructor-arg>
<map></map>
</constructor-arg>
</bean>
</array>
</entry>
</map>
</constructor-arg>
</bean>
</property>
<property name="authorityGranters">
<list>
<!-- You will need to write your own implementation of AuthorityGranter -->
<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
</list>
</property>
</bean>
xml

JaasAuthenticationProvider

JaasAuthenticationProvider 假设默认的 ConfigurationConfigFile 的一个实例。这个假设是为了尝试更新 Configuration。然后,JaasAuthenticationProvider 使用默认的 Configuration 来创建 LoginContext

假设我们有一个 JAAS 登录配置文件 /WEB-INF/login.conf,其内容如下:

JAASTest {
sample.SampleLoginModule required;
};
txt

像所有 Spring Security 的 bean 一样,JaasAuthenticationProvider 也是通过应用程序上下文来配置的。以下定义将对应于上述 JAAS 登录配置文件:

<bean id="jaasAuthenticationProvider"
class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="/WEB-INF/login.conf"/>
<property name="loginContextName" value="JAASTest"/>
<property name="callbackHandlers">
<list>
<bean
class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler"/>
<bean
class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler"/>
</list>
</property>
<property name="authorityGranters">
<list>
<bean class="org.springframework.security.authentication.jaas.TestAuthorityGranter"/>
</list>
</property>
</bean>
xml

以主体身份运行

如果已配置,JaasApiIntegrationFilter 会尝试以 JaasAuthenticationToken 上的 Subject 身份运行。这意味着可以使用以下方式访问 Subject

Subject subject = Subject.getSubject(AccessController.getContext());
java

您可以使用 jaas-api-provision 属性来配置此集成。当与依赖于 JAAS Subject 被填充的遗留或外部 API 集成时,此功能非常有用。