# Java 身份验证和授权服务提供者

## 概述

Spring 安全性提供了一种包，能够将身份验证请求委托给 Java 身份验证和授权服务。下面将详细讨论这个包。

## 抽象 JaasAuthenticationProvider

`AbstractJaasAuthenticationProvider`是所提供的 JAAS`AuthenticationProvider`实现的基础。子类必须实现创建`LoginContext`的方法。`AbstractJaasAuthenticationProvider`具有许多可以注入其中的依赖项，这些依赖项将在下面讨论。

### JAAS CallbackHandler

大多数 JAAS`LoginModule`s 都需要某种类型的回调。这些回调通常用于从用户获得用户名和密码。

在 Spring 安全性部署中， Spring 安全性负责此用户交互（通过身份验证机制）。因此，在将身份验证请求委托给 JAAS 时， Spring Security 的身份验证机制将已经完全填充了一个`Authentication`对象，该对象包含 JAAS`LoginModule`所需的所有信息。

因此， Spring Security 的 JAAS 包提供了两个默认的回调处理程序，`JaasNameCallbackHandler`和`JaasPasswordCallbackHandler`。这些回调处理程序中的每一个都实现`JaasAuthenticationCallbackHandler`。在大多数情况下，这些回调处理程序可以在不了解内部机制的情况下简单地使用。

对于那些需要完全控制回调行为的人，内部`AbstractJaasAuthenticationProvider`将这些`JaasAuthenticationCallbackHandler`s 包装成`InternalCallbackHandler`。`InternalCallbackHandler`是实际实现 JAASNormal`CallbackHandler`接口的类。每当使用 JAAS`LoginModule`时，都会传递一个配置`InternalCallbackHandler`s 的应用程序上下文列表。如果`LoginModule`对`InternalCallbackHandler`s 请求回调，则回调依次传递给正在打包的`JaasAuthenticationCallbackHandler`s。

### Jaas AuthorityGranter

JAAS 与校长一起工作。在 JAAS 中，甚至连“角色”也被表示为主体。 Spring 另一方面，安全性适用于`Authentication`对象。每个`Authentication`对象包含一个主体，以及多个`GrantedAuthority`s。为了便于在这些不同概念之间进行映射， Spring Security 的 JAAS 包包括一个`AuthorityGranter`接口。

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

Spring 考虑到每个 JAAS 主体都具有特定于实现的含义，安全性不包括任何`AuthorityGranter`s 的产品。然而，在单元测试中有一个`TestAuthorityGranter`演示了一个简单的`AuthorityGranter`实现。

## DefaultJaasAuthenticationProvider

`DefaultJaasAuthenticationProvider`允许将 JAAS`Configuration`对象作为依赖项注入其中。然后，它使用注入的 JAAS创建。这意味着`DefaultJaasAuthenticationProvider`不绑定`Configuration`作为`JaasAuthenticationProvider`的任何特定实现。

### 记忆组态

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

### 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>
```

## JaasAuthenticationProvider

`JaasAuthenticationProvider`假设默认的`Configuration`是[配置文件](https://docs.oracle.com/javase/8/docs/jre/api/security/jaas/spec/com/sun/security/auth/login/ConfigFile.html)的实例。这个假设是为了尝试更新`Configuration`。然后`JaasAuthenticationProvider`使用默认的`Configuration`来创建`LoginContext`。

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

```
JAASTest {
	sample.SampleLoginModule required;
};
```

与所有 Spring 安全 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>
```

## 以跑步为主题

如果进行了配置，`JaasApiIntegrationFilter`将尝试在`JaasAuthenticationToken`上以`Subject`的形式运行。这意味着`Subject`可以通过以下方式访问：

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

可以使用[JAAS-API-供应](../appendix/namespace/http.html#nsa-http-jaas-api-provision)属性轻松配置此集成。当与依赖于填充的 JAAS 主题的遗留或外部 API 集成时，此功能非常有用。

[预先认证](preauth.html)[CAS](cas.html)

