31. Java 身份验证和授权服务(JAAS)提供程序
31.1 Overview
Spring Security 提供了一个程序包,可以将身份验证请求委派给 Java 身份验证和授权服务(JAAS)。该软件包将在下面详细讨论。
31.2 AbstractJaasAuthenticationProvider
AbstractJaasAuthenticationProvider
是所提供的 JAAS AuthenticationProvider
实现的基础。子类必须实现创建LoginContext
的方法。 AbstractJaasAuthenticationProvider
具有许多可以注入到其中的依赖项,下面将对此进行讨论。
31.2.1 JAAS CallbackHandler
大多数 JAAS LoginModule
都需要某种回调。这些回调通常用于从用户获取用户名和密码。
在 Spring Security 部署中,Spring Security 负责此用户交互(通过身份验证机制)。因此,在将身份验证请求委托给 JAAS 时,Spring Security 的身份验证机制将已经完全填充了Authentication
对象,其中包含 JAAS LoginModule
所需的所有信息。
因此,Spring Security 的 JAAS 包提供了两个默认的回调处理程序JaasNameCallbackHandler
和JaasPasswordCallbackHandler
。这些回调处理程序中的每一个都实现JaasAuthenticationCallbackHandler
。在大多数情况下,无需了解内部机制即可简单地使用这些回调处理程序。
对于需要完全控制回调行为的用户,内部AbstractJaasAuthenticationProvider
将这些JaasAuthenticationCallbackHandler
换成InternalCallbackHandler
。 InternalCallbackHandler
是实际实现 JAAS 常规CallbackHandler
接口的类。每当使用 JAAS LoginModule
时,都会向其传递配置了InternalCallbackHandler
的应用程序上下文列表。如果LoginModule
请求针对InternalCallbackHandler
的回调,则该回调又传递给正在包装的JaasAuthenticationCallbackHandler
。
31.2.2 JAAS AuthorityGranter
JAAS 与校长合作。 JAAS 中甚至将“角色”表示为主体。另一方面,Spring Security 可以处理Authentication
个对象。每个Authentication
对象包含一个主体和多个GrantedAuthority
。为了促进这些不同概念之间的 Map,Spring Security 的 JAAS 软件包包括一个AuthorityGranter
接口。
AuthorityGranter
负责检查 JAAS 委托人并返回一组String
,代表分配给委托人的权限。对于每个返回的授权字符串,AbstractJaasAuthenticationProvider
创建一个JaasGrantedAuthority
(它实现 Spring Security 的GrantedAuthority
接口),其中包含授权字符串和AuthorityGranter
传递的 JAAS 主体。 AbstractJaasAuthenticationProvider
首先通过使用 JAAS LoginModule
成功验证用户的凭据,然后访问它返回的LoginContext
,从而获得 JAAS 主体。调用LoginContext.getSubject().getPrincipals()
,并将每个结果主体传递给针对AbstractJaasAuthenticationProvider.setAuthorityGranters(List)
属性定义的每个AuthorityGranter
。
鉴于每个 JAAS 主体都具有特定于实现的含义,因此 Spring Security 不包含任何生产AuthorityGranter
。但是,单元测试中有一个TestAuthorityGranter
演示了一个简单的AuthorityGranter
实现。
31.3 DefaultJaasAuthenticationProvider
DefaultJaasAuthenticationProvider
允许将 JAAS Configuration
对象作为依赖项注入到该对象中。然后,使用注入的 JAAS Configuration
创建一个LoginContext
。这意味着DefaultJaasAuthenticationProvider
和JaasAuthenticationProvider
一样不受Configuration
的任何特定实现的约束。
31.3.1 InMemoryConfiguration
为了便于将Configuration
注入DefaultJaasAuthenticationProvider
,提供了默认的内存实现InMemoryConfiguration
。实现构造函数接受一个Map
,其中每个键代表一个登录配置名称,该值代表一个AppConfigurationEntry
的Array
。 InMemoryConfiguration
还支持AppConfigurationEntry
对象的默认Array
,如果在提供的Map
中找不到 Map,则将使用它们。有关详细信息,请参考InMemoryConfiguration
的类级别 javadoc。
31.3.2 DefaultJaasAuthenticationProvider 示例配置
尽管InMemoryConfiguration
的 Spring 配置比标准 JAAS 配置文件更冗长,但与DefaultJaasAuthenticationProvider
结合使用时,它比JaasAuthenticationProvider
更灵活,因为它不依赖于默认的Configuration
实现。
以下提供了使用InMemoryConfiguration
的DefaultJaasAuthenticationProvider
的示例配置。请注意,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>
31.4 JaasAuthenticationProvider
JaasAuthenticationProvider
假定默认的Configuration
是ConfigFile的实例。进行此假设是为了尝试更新Configuration
。 JaasAuthenticationProvider
然后使用默认的Configuration
创建LoginContext
。
假设我们有一个 JAAS 登录配置文件/WEB-INF/login.conf
,其内容如下:
JAASTest {
sample.SampleLoginModule required;
};
像所有 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>
31.5 以主题身份运行
如果已配置,则JaasApiIntegrationFilter
将尝试在JaasAuthenticationToken
上以Subject
的身份运行。这意味着可以使用以下命令访问Subject
:
Subject subject = Subject.getSubject(AccessController.getContext());
可以使用jaas-api-provision属性轻松配置此集成。与依赖于填充 JAAS 主题的旧版或外部 API 集成时,此功能很有用。