Tomcat:单个Web应用程序的多种身份验证方案?

时间:2013-07-16 10:03:47

标签: java java-ee authentication tomcat forms-authentication

我的Web应用程序使用内部Web API(来自浏览器的简单AJAX请求,因为它是主要客户端),最终应该在第三方外部公开。由于API必须受web.xml中的安全约束保护,因此必须对用户或客户端进行身份验证。目前,有一个自定义表单身份验证器实现,它执行一些额外的检查和操作,然后简单地将进一步的身份验证处理委托给自定义身份验证器派生自的FormAuthenticator类。这非常好用,因为用户只是被迫登录并通过身份验证,而唯一的客户端是Web浏览器。

但是FORM身份验证不适合其他类型的客户端:假设有一个Android客户端,各种第三方客户端等。要通过表单身份验证,他们都必须模拟我在这个问题中寻找的行为:{ {3}}。在对Tomcat源代码进行一些调查之后,我已经知道应该可以扩展AuthenticatorBase类来实现自己的身份验证方式(如FormAuthenticatorBasicAuthenticator.java) 。我试图做的是:

public final class SimpleAuthenticator extends AuthenticatorBase {

    private static final String USERNAME_PARAMETER = "username";
    private static final String PASSWORD_PARAMETER = "password";

    @Override
    protected boolean authenticate(Request request, Response response, LoginConfig config) throws IOException {
        final Principal principal = request.getUserPrincipal();
        final String ssoId = (String) request.getNote(REQ_SSOID_NOTE);
        if ( principal != null ) {
            if ( ssoId != null ) {
                associate(ssoId, request.getSessionInternal(true));
            }
            return true;
        }
        if ( ssoId != null && reauthenticateFromSSO(ssoId, request) ) {
            return true;
        }
        final String contextPath = request.getContextPath();
        final String requestURI = request.getDecodedRequestURI();
        final boolean login = requestURI.equals(contextPath + "/authenticate");
        if ( !login ) {
            response.sendError(SC_FORBIDDEN);
            return false;
        }
        final String username = request.getParameter(USERNAME_PARAMETER);
        final String password = request.getParameter(PASSWORD_PARAMETER);
        final Realm realm = context.getRealm();
        final Principal authenticatedUserPrincipal = realm.authenticate(username, password);
        if ( authenticatedUserPrincipal == null ) {
            response.sendError(SC_UNAUTHORIZED);
            return false;
        }
        register(request, response, authenticatedUserPrincipal, "SIMPLE", username, password);
        return true;
    }

}

简单来说,我想使用/%CONTEXT_PATH%/authenticate?username=%USERNAME%&password=%PASSWORD%之类的内容来使用自定义非格式SimpleAuthenticator对用户进行身份验证。不确定BasicAuthentication对于这种情况是否会更好,但我在上面的示例中遇到了以下问题:

  • Tomcat允许在Valve中指定多个context.xml。如果将另一个身份验证器添加到context.xml文件中,则每个身份验证器都会处理每个安全资源。 (原则上,我理解为什么会发生这种情况,但它们是否可以针对不同的资源分开?)
  • /%CONTEXT_PATH%/authenticate无法访问(HTTP 404)。 (不清楚是否知道/j_security_check是以某种方式进行模拟的。)
  • 我找不到在Tomcat中指定多个身份验证方案的方法,因此“旧”Web浏览器客户端仍然可以使用FormAuthenticator(就像今天一样),但“轻量级”客户端可以使用我试图用SimpleAuthenticator实现的简化身份验证。 (甚至不知道是否可能 - 这是核心)
  • 据我所知,servlet规范只允许一个login-config用于整个Web应用程序。 (那么,我应该使用其他网络应用程序来提供API吗?)
  • 我看到一些提及通过Filter实现自定义身份验证,但是如果可能的话 - 我想将身份验证器模块分开放在一个地方(就像它已经存在并通过{{3}确认) })。但是,我很乐意回顾一下我从头开始使用的一般概念。

我怀疑我做了一件非常错误的事情并且完全理解,但我不相信在Tomcat中无法实现多种身份验证方案。

有没有办法提供多种身份验证方案来从FormAuthetication中提取身份验证(对于轻量级客户端)?非常感谢您的帮助。提前谢谢。

1 个答案:

答案 0 :(得分:2)

底线:您无法在Tomcat中为同一Web应用程序配置多个身份验证方案。 您可以在web.xml

中配置一个用于身份验证的身份验证方法
<login-config>
    <auth-method>CLIENT-CERT</auth-method>
</login-config>

用于Web应用程序身份验证的身份验证器上的Tomcat映射。 例如,对于CLIENT-CERT,它将使用org.apache.catalina.authenticator.SSLAuthenticator 映射位于文件org/apache/catalina/startup/Authenticators.properties

为了您在问题中描述的目的,您可以使用常规的Tomcat表单身份验证器(<auth-method>FORM</auth-method>

以下代码将对用户进行身份验证:

String url = "j_security_check?j_username=" + username + "&j_password=" + password;
String redirectUrl = response.encodeRedirectURL(url);
response.sendRedirect(redirectUrl);

首次访问应用程序时,按上述执行URL对用户进行身份验证。 此外,您可以使用表单身份验证器“旧”代码:) 请注意,上面的代码使用GET方法。 我建议将POST方法中的相同参数提交给j_security_check(您可以在AJAX中执行此操作)。