Java webapp的多重登录配置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6150443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 14:33:51  来源:igfitidea点击:

Multiple login-config for Java webapp

javaweb-applicationslogin

提问by hage

I have a Java web application that has a website for user interactions. To authenticate users I configured the application via web.xml to use FORM-based authentication. Users are forwarded to a login page and everything is fine so far.

我有一个 Java Web 应用程序,它有一个用于用户交互的网站。为了对用户进行身份验证,我通过 web.xml 将应用程序配置为使用基于 FORM 的身份验证。用户被转发到登录页面,到目前为止一切都很好。

Now we are developing a desktop client (in C#) for this web application which accesses the application via RESTful web services. I implemented these services in the same web app as the web site and of course the caller of the web service should be authenticated too. But now I'm facing the problem, that whenever I call a web service the server is returning the login page's HTML as response.

现在我们正在为此 Web 应用程序开发桌面客户端(在 C# 中),它通过 RESTful Web 服务访问该应用程序。我在与网站相同的 Web 应用程序中实现了这些服务,当然 Web 服务的调用者也应该进行身份验证。但是现在我面临的问题是,每当我调用 Web 服务时,服务器都会返回登录页面的 HTML 作为响应。

I think it would be cool to be able to use another login-config for my REST service servlet (which would probably use BASIC authentication then).

我认为能够为我的 REST 服务 servlet 使用另一个登录配置(那时它可能会使用 BASIC 身份验证)会很酷。

Google didn't bring up much, but I can't believe I'm the first one being in such situation. So I would like to hear your thoughts and solutions.

谷歌没有提出太多,但我不敢相信我是第一个遇到这种情况的人。所以我想听听你的想法和解决方案。

Any hint is appreciated.

任何提示表示赞赏。

采纳答案by Ramesh PVK

The only solution is have two apps for two clients having different login mechanisms. The application code should be seperated and move it common app to which these apps with forward the requests.

唯一的解决方案是为具有不同登录机制的两个客户端提供两个应用程序。应用程序代码应该分开,并将其移动到这些应用程序转发请求的通用应用程序。

Else, use your custom authentication.

否则,请使用您的自定义身份验证。

回答by BZoli

I had the same problem, and a couldn't find solution. You can define multiple authentication methods: http://docs.oracle.com/cd/E24329_01/web.1211/e24485/thin_client.htm#SCPRG164But: Unfortunately, both FORM and BASIC cannot exist together in the list of auth-method values.

我遇到了同样的问题,找不到解决方案。您可以定义多种身份验证方法:http: //docs.oracle.com/cd/E24329_01/web.1211/e24485/thin_client.htm#SCPRG164但是:不幸的是,在 auth-method 列表中不能同时存在 FORM 和 BASIC值。

回答by Maurice Perry

I've solved this problem with a tomcat valve. The valve checks for the presence of an Authorization header, in which case, the header is used as credentials to authenticate the user, otherwise, the normal authentication method takes place.

我已经用一个 tomcat 阀门解决了这个问题。Valve 检查 Authorization 标头是否存在,在这种情况下,标头用作验证用户的凭据,否则,将使用正常的身份验证方法。

Here is the code of the Valve:

这是阀门的代码:

package org.tastefuljava.tomcat;

import java.io.IOException;
import java.security.Principal;
import javax.servlet.ServletException;
import org.apache.catalina.Realm;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

public class AutoBasicValve extends ValveBase {
    private static final String BASIC_PREFIX = "basic ";

    private String encoding = "UTF-8";

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    @Override
    public void invoke(Request request, Response response)
            throws IOException, ServletException {
        Principal principal = request.getUserPrincipal();
        Realm realm = getContainer().getRealm();
        if (principal != null) {
            if (containerLog.isDebugEnabled()) {
                containerLog.debug(
                        "Already authenticated as: " + principal.getName());
            }
        } else if (realm == null) {
            if (containerLog.isDebugEnabled()) {
                containerLog.debug("No realm configured");
            }
        } else {
            String auth = request.getHeader("authorization");
            if (auth != null) {
                if (auth.toLowerCase().startsWith(BASIC_PREFIX)) {
                    auth = auth.substring(BASIC_PREFIX.length());
                    byte[] bytes = Base64.decode(auth);
                    auth = new String(bytes, encoding);
                    int ix = auth.indexOf(':');
                    if (ix >= 0) {
                        String username = auth.substring(0, ix);
                        String password = auth.substring(ix+1);
                        principal = realm.authenticate(username, password);
                        if (principal == null) {
                            containerLog.warn(
                                    "Could not authenticate " + username);
                        } else {
                            containerLog.info(
                                    "Authenticated as " + principal.getName());
                            request.setAuthType("BASIC");
                            request.setUserPrincipal(principal);
                        }
                    }
                }
            }
        }
        getNext().invoke(request, response);
    }
}

You can use the valve by adding a <Valve> tag either in the server.xml file in your tomcat installation, or in the META-INF/context.xml file of your WebApp:

您可以通过在 tomcat 安装的 server.xml 文件或 WebApp 的 META-INF/context.xml 文件中添加 <Valve> 标记来使用该阀:

The project is on github: https://github.com/robbyn/mydsrealm

项目在github上:https: //github.com/robbyn/mydsrealm

回答by TFR

Unfortunately login-config is not mapped like filters and servlets are so there is only one global to the webapp. That means you either need 2 webapps or if on JBoss, you can use the WebAuthentication class to inform the container of your app's programatic login. However, if you are using embedded jetty or other web servers, there is absolutely no way to support BASIC and FORM off together using web.xml. You would have to write a custom authentication service

不幸的是 login-config 不像过滤器和 servlet 那样映射,所以 webapp 只有一个全局的。这意味着您需要 2 个 web 应用程序,或者如果在 JBoss 上,您可以使用 WebAuthentication 类将您的应用程序的程序登录通知容器。但是,如果您使用嵌入式 jetty 或其他 Web 服务器,则绝对无法使用 web.xml 来同时支持 BASIC 和 FORM。您必须编写自定义身份验证服务

However, you can convert to Apache Shiro and it will solve these issues in an amazingly well written, simple design. These steps will allow REST clients to use either BASIC auth on every page without a session cookie or login at /rest/login and receive a session. Browser clients can then use FORM auth

但是,您可以转换为 Apache Shiro,它将以非常出色的简单设计解决这些问题。这些步骤将允许 REST 客户端在没有会话 cookie 的情况下在每个页面上使用 BASIC 身份验证或登录 /rest/login 并接收会话。浏览器客户端然后可以使用 FORM auth

1) protect /login with "authc", set shiro.loginUrl to /login and host an HTML form at that location
2) protect /rest/login with "anon" and write a URL handler for POST with this code
    UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
    token.setRememberMe(rememberMe);
    SecurityUtils.getSubject().login(token);
3) protect /rest/logout with "logout"
4) protect /rest/** with "noSessionCreation, authcBasic, rest"

回答by SScholl

Me helped https://wiki.apache.org/tomcat/SSLWithFORMFallbackin combination with this tomcat valveto allow SSL client certs and form and basic fallback authentication.

我帮助https://wiki.apache.org/tomcat/SSLWithFORMFallback结合这个tomcat 阀来允许 SSL 客户端证书以及表单和基本回退身份验证。

Best regards

最好的祝福