java - Tomcat - 没有领域的 SSO?

标签 java session tomcat cookies

我正在尝试在 Tomcat 下启用 SSO,以便访问 http://mydomain.com 的用户和 http://www.mydomain.com将有他们的 session cookie 可用于向 http://subdomain.mydomain.com 发出的请求.所有这三个域都转到同一个 Web 应用程序,因此理想情况下,我根本不想搞乱 SSO,只是在标准 JSESSIONID cookie 上设置域。

但是,这似乎不可能,所以我正在尝试启用 Tomcat 的 SSO Valve。问题是 Valve 需要一个 Realm 的定义,而 Realm 应该指定一个用户和角色的数据库。但是,我没有使用基于容器的身份验证,也没有使用基于角色的授权,所以我不需要也不想配置 Realm。我只想让 session cookie 能够在这些不同的子域中的每一个之间共享。

有什么简单的方法可以做到这一点吗?

编辑

我目前的解决方法是让服务器将每个传入请求重定向到“规范”服务器名称。这工作得很好,但显然它并没有真正解决问题。

最佳答案

我们遇到了同样的问题并创建了一个 Tomcat Valve,它将覆盖或设置 session Cookie 的域部分。很简单的事情,它已经工作了很多年。代码是这样的:

public class CrossSubdomainSessionValve extends ValveBase {
  public CrossSubdomainSessionValve() {
    super();
    info = "common-tomcat-CrossSubdomainSessionValve";
  }

  @Override
  public void invoke(Request request, Response response) throws IOException, ServletException {
    // cookie will only need to be changed, if this session is created by this request.
    if (request.getSession(true).isNew()) {
      Cookie sessionCookie = findSessionCookie(response.getCookies());
      if (sessionCookie != null) {
        String cookieDomainToSet = getCookieDomainToSet(request.getServerName());
        if (cookieDomainToSet != null) {
          // changing the cookie only does not help, because tomcat immediately sets
          // a string representation of this cookie as MimeHeader, thus we also
          // have to change this representation
          replaceCookie(response.getCoyoteResponse().getMimeHeaders(), sessionCookie, cookieDomainToSet);
        }
      }
    }

    // process the next valve
    getNext().invoke(request, response);
  }

  protected Cookie findSessionCookie(Cookie[] cookies) {
    if (cookies != null)
      for (Cookie cookie : cookies)
        if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) {
          return cookie;
    return null;
  }

  protected void replaceCookie(MimeHeaders headers, Cookie originalCookie, String domainToSet) {
    // if the response has already been committed, our replacementstrategy will have no effect

    // find the Set-Cookie header for the existing cookie and replace its value with new cookie
    for (int i = 0, size = headers.size(); i < size; i++) {
      if (headers.getName(i).equals("Set-Cookie")) {
        MessageBytes value = headers.getValue(i);
        if (value.indexOf(originalCookie.getName()) >= 0) {
          if (originalCookie.getDomain() == null) {
            StringBuilder builder = new StringBuilder(value.getString()).append("; Domain=").append(domainToSet);
            value.setString(builder.toString());
          } else {
            String newDomain = value.getString().replaceAll("Domain=[A-Za-z0-9.-]*", "Domain=" + domainToSet);
            value.setString(newDomain);
          }
        }
      }
    }
  }

  protected String getCookieDomainToSet(String cookieDomain) {
    String[] parts = cookieDomain.split("\\.");
    if (parts.length >= 3) {
      return "." + parts[parts.length - 2] + "." + parts[parts.length - 1];
    }
    return null;
  }

  public String toString() {
    return ("CrossSubdomainSessionValve[container=" + container.getName() + ']');
  }
}

该算法的工作原理如下: - 仅当 session 是新的时 - 查找 session cookie - 获取请求的主机名 - 用“.”分割主机名 - 如果它至少有 3 个部分(如 www.google.de),删除第一部分(到 .google.de) - 重置 cookie

在您的上下文配置中,您可以像这样应用阀门

<Valve className="my.package.CrossSubdomainSessionValve" httpOnlyEnabled="true" />

警告:在代码中,如果之前没有创建 session ,Valve 会创建一个 session ,并且根本不关心您是否需要 session ...

希望对您有所帮助...祝您好运!

关于java - Tomcat - 没有领域的 SSO?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7034536/

相关文章:

java - 如何使用 Jackson 以自定义方式实例化 bean?

java - 如果有效,为什么其他方法不起作用?

php - 在 php 中保护 session 变量的有效方法是什么?

session - 在 context.Context 中添加多个键值来自 Web 服务 API

java - 使用 cargo 插件调试 Tomcat 部署的代码

apache - Tomcat Manager 能否在替代路径上安全运行?

java - 在 Swing 中保持 View 状态

java - Spring Batch 或 BIRT 框架

android - 使用 Android-query 和 AjaxCallback 设置 cookie

java - 生产中的Solr