加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 具有多个WebAppContext实例的单一登录Jetty

发布时间:2020-12-15 02:13:46 所属栏目:Java 来源:网络整理
导读:我有一个嵌入式jetty服务器,它从许多不同的位置迭代一个webapps列表(列表在不同的部署之间).我正在尝试从基本身份验证转换为表单身份验证. 我想做的是: // create constraintConstraint usersOnly = new Constraint(Constraint.__FORM_AUTH,"user");usersOn
我有一个嵌入式jetty服务器,它从许多不同的位置迭代一个webapps列表(列表在不同的部署之间).我正在尝试从基本身份验证转换为表单身份验证.

我想做的是:

// create constraint
Constraint usersOnly = new Constraint(Constraint.__FORM_AUTH,"user");
usersOnly.setAuthenticate(true);
ConstraintMapping requireAuthentication = new ConstraintMapping();
requireAuthentication.setConstraint(usersOnly);
requireAuthentication.setPathSpec("/*");

// create login service
LoginService loginService = new HashLoginService("realm");
loginService.setConfig("users.txt");

// create form authentication
FormAuthenticator formAuthenticator = new FormAuthenticator("/login","/login",true);

// create /login route
ServletHolder loginServlet = new ServletHolder(new DefaultServlet() {
@Override
  protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException {
    response.getWriter().append("<html>n<head>n<title>Login</title>n</head>n<body>n"
    + "<form method='POST' action='/j_security_check'>n"
    + "<input type='text' name='j_username'/>n"
    + "<input type='password' name='j_password'/>n"
    + "<input type='submit' value='Login'/>n</form>n</body>n</html>n");
  }
});

ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
securityHandler.addMapping(requireAuthentication);
securityHandler.setLoginService(loginService);
securityHandler.setAuthenticator(formAuthenticator);

// assign security to each webapp
for (WebAppContext webapp : webapps) {
  webapp.setSecurityHandler(securityHandler);
  webapp.addServlet(loginServlet,"/login");
}

如果webapps中只有一个webapp,则可以正常工作,但如果有多个webapp,则每次跟踪从一个webapp到另一个webapp的链接时都会提示您登录,每次重新进行身份验证时,都会被重定向到基础webapp.路由“/”并且仅针对该路由进行身份验证.

我想让我的背景分享会话.

根据this question,为每个WebAppContext实例配置一个公共SessionManager应该可以解决问题,但是asker只有一个WebAppContext实例.如果我尝试将相同的SessionManager实例分配给每个WebAppContext,我会得到NPE.

我还看到一些资源指向将每个上下文的SessionCookieConfig的路径设置为公共上下文路径,并将useRequestedId设置为每个WebAppContext的SessionManager的true,但此解决方案适用于org.mortbay.jetty并且已过时.

如果您对具有多个WebAppContexts的嵌入式Jetty服务器设置SSO有任何见解或经验,或者如果您能想到使用一个公共服务器提供多个不同Web应用程序的更好方法,请指出我正确的方向.

如何通过填写单个表单允许用户对一台服务器处理的所有Web应用进行身份验证?

如果我不清楚或者您有任何疑问,请告诉我.

解决方法

我的解决方案是扩展HashSessionManager类,以便在创建新会话之前查询SessionIdManager.结果是同一个SessionIdManager下的CrossContextSessionManager实例共享会话内容而不仅仅是会话ID.因此,登录一个webapp意味着全部登录.

import java.util.Collection;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.eclipse.jetty.server.session.AbstractSession;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;

/**
 * Allows the WebAppContext to check the server's SessionIdManager before creating a new session
 * so that WebAppContext can share session contents for each client rather than just session ids.
 */
public class CrossContextSessionManager extends HashSessionManager {

  // Number of seconds before the user is automatically logged out of an idle webapp session
  private int defaultSessionTimeout = 1800;

  /**
   * Check for an existing session in the session id manager by the requested id.
   * If no session has that id,create a new HttpSession for the request.
   */
  @Override
  public HttpSession newHttpSession(HttpServletRequest request) {
    AbstractSession session = null;

    String requestedId = request.getRequestedSessionId();
    if (requestedId != null) {
      String clusterId = getSessionIdManager().getClusterId(requestedId);
      Collection<HttpSession> sessions = ((HashSessionIdManager) getSessionIdManager()).getSession(clusterId);
      for (HttpSession httpSession : sessions) {
        session = (AbstractSession) httpSession;
        break;
      }
    }

    if (session == null) {
      session = newSession(request);
      session.setMaxInactiveInterval(defaultSessionTimeout);
      addSession(session,true);
    }

    return session;
  }
}

如果请求已经携带了一个id,那么newSessionId只会从中提取该id.否则,它将从所有现有ID创建唯一的新ID.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读