3.4. 主题(Subject)验证


主题验证要求 JAAS 登录。登录过程由下列要点组成:
  1. LoginModule 配置所要求的,用程序实例化一个 LoginContext 并传入登录配置的名称和 CallbackHandler 来填充 Callback 对象。
  2. LoginContext 咨询 Configuration 来加载包括在命名登录配置里的所有 LoginModules。如果不存在这个名称的配置,那么默认会使用 other 配置。
  3. 应用程序调用 LoginContext.login 方法。
  4. 登录模块调用所有加载的 LoginModule。每个 LoginModule 都会试图验证这个主题,它调用相关联的 CallbackHandler 上的 handle 犯法来获取验证过程所需的信息。这些信息以 Callback 对象队列的方式被传入 handle 方法。成功后,LoginModule 将主题和相关的主体(principal)和凭证关联。
  5. LoginContext 返回验证状态给应用程序。从 login 方法返回则表示成功。如果 login 方法抛出异常则表示失败。
  6. 如果验证成功,应用程序使用 LoginContext.getSubject 方法获取已验证的主题。
  7. 在主题验证的作用域完成后,所有的主体以及和 login 方法的主题相关的信息都可以通过调用 LoginContext.logout 方法进行删除。
LoginContext 类提供了用于验证主题的基本方法以及开发独立于底层验证技术的应用程序的途径。LoginContext 咨询 Configuration 来决定为特定应用程序配置的验证服务。LoginModule 类代表验证服务。因此,你可以插入不同的等录模块到应用程序而无需修改应用程序自身。下面的步骤显示了应用程序验证主题所需的步骤。
CallbackHandler handler = new MyHandler();
LoginContext lc = new LoginContext("some-config", handler);

try {
    lc.login();
    Subject subject = lc.getSubject();
} catch(LoginException e) {
    System.out.println("authentication failed");
    e.printStackTrace();
}
                        
// Perform work as authenticated Subject
// ...

// Scope of work complete, logout to remove authentication info
try {
    lc.logout();
} catch(LoginException e) {
    System.out.println("logout failed");
    e.printStackTrace();
}
                        
// A sample MyHandler class
class MyHandler 
    implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws
        IOException, UnsupportedCallbackException
    {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                NameCallback nc = (NameCallback)callbacks[i];
                nc.setName(username);
            } else if (callbacks[i] instanceof PasswordCallback) {
                PasswordCallback pc = (PasswordCallback)callbacks[i];
                pc.setPassword(password);
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                                                       "Unrecognized Callback");
            }
        }
    }
}
Copy to Clipboard Toggle word wrap
开发者通过创建 LoginModule 接口的实现集成验证技术。这允许管理员插入不同的验证技术到应用程序里。你可以将多个 LoginModule 链接在一起来允许多种验证技术来参与验证过程。例如,一个 LoginModule 可以执行基于用户/密码的验证,而另外一个则可以连接硬件设备如智能卡读写器或生物特征识别器。
LoginModule 的生命周期是由客户创建和发行 login 方法所根据的 LoginContext 对象驱动的。这个过程由两阶段组成:
  • LoginContext 使用其公共的 no-arg 构造器创建每个已配置的 LoginModule
  • 每个 LoginModule 都是通过其 initialize 方法来初始化的。Subject 参数需保证是非 null 的。initialize 方法的签名是:public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
  • login 被调用来启动验证过程。例如,某个方法实现可能提示用户输入用户名和密码,然后根据存储在命名服务(如 NIS 或 LDAP)里的数据进行检验。其他的实现可能连接智能卡和生物设备,或者简单地从底层操作系统抽取信息。每个 LoginModule 对用户标识符的检验会在 JAAS 验证的第一阶段来考虑。login 方法的签名是 boolean login() throws LoginExceptionLoginException 表示失败。返回值为 true 表示方法调用成功,而 false 表示登录模块应该被忽略。
  • 如果 LoginException 的总体验证成功,commit 将在每个 LoginModule 上调用。如果 LoginModule 的第一阶段验证成功,commit 方法将继续第二阶段并将相关的主体、公共凭证和/或私有凭证和关联主题。如果 LoginModule 的第一阶段失败,那 commit 将删除任何之前保存的验证状态,如用户名或密码。commit 方法的签名是:boolean commit() throws LoginExceptionLoginException 的抛出表示完成提交阶段失败。返回值为 true 表示方法调用成功,而 false 表示登录模块应该被忽略。
  • 如果 LoginException 的总体验证失败,abort 将在每个 LoginModule 上调用。abort 方法删除或销毁任何之前 login 或 initialize 方法创建的验证状态。abort 方法的签名是:boolean abort() throws LoginExceptionLoginException 的抛出表示完成 abort 阶段失败。返回值为 true 表示方法调用成功,而 false 表示登录模块应该被忽略。
  • 要在成功登录后删除验证状态,应用程序将调用 LoginContext 上的 logout。这会导致在每个 LoginModule 上调用 logout 方法。logout 方法删除原来在 commit 阶段和主题相关联的主体和凭证。凭证应该在删除时被销毁。logout 方法的签名是:boolean logout() throws LoginExceptionLoginException 的抛出表示完成登出阶段失败。返回值为 true 表示方法调用成功,而 false 表示登录模块应该被忽略。
LoginModule 必须和用户进行通讯来获取验证信息时,它使用 CallbackHandler 对象。应用程序实现 CallbackHandler 接口并将其传入 LoginContext,这会直接发送验证信息到底层的等录模块。
登录模块使用 CallbackHandler 来获取用户的输入,如密码或智能卡 PIN,并提供信息给用户,如状态信息。通过允许应用程序指定 CallbackHandler,底层的 LoginModule 保持对应用程序和用户交互的独立。例如,GUI 应用程序的 CallbackHandler 实现可能显示一个窗口来让用户输入。另一方面,非 GUI 的应用程序可能 CallbackHandler 简单地使用应用服务器的 API 来获取凭证信息。 CallbackHandler 接口有一个方法需要被实现:
void handle(Callback[] callbacks)
    throws java.io.IOException, 
           UnsupportedCallbackException;
Copy to Clipboard Toggle word wrap
Callback 接口是我们最后将了解的验证类。它是为几个默认实现提供的一个标记接口,其中包括 NameCallback 和在以前示例里使用的 PasswordCallbackLoginModule 使用 Callback 来请求验证机制所需的信息。在验证的登录阶段,LoginModule 将一个 Callback 队列直接传入 CallbackHandler.handle 方法。如果 callbackhandler 无法理解如何使用传递到 handle 方法的 Callback,它会抛出 UnsupportedCallbackException 来中止 login 的调用。
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat