You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetty单Web应用同时支持FORM与OpenID双认证方案咨询

Absolutely, there are solid solutions to get both FORM and OpenID authentication working side-by-side for your Jetty 9.4.32 web app without redeploys or duplicate deployments. Here are two practical approaches you can implement:

方案1:基于URL路径的认证分流

This approach lets you map specific URL patterns to different authentication methods—e.g., /openid/** uses OpenID, while /form/** uses FORM auth. Users can access the protected resources via their preferred path, and Jetty will automatically trigger the right auth flow.

Step 1: Configure Context XML with Dual Security Handlers

Update your context XML to define two separate ConstraintSecurityHandler instances, each tied to a different authentication method and URL path:

<Set name="handler">
  <New class="org.eclipse.jetty.server.handler.HandlerCollection">
    <Set name="handlers">
      <Array type="org.eclipse.jetty.server.Handler">
        <!-- OpenID Authentication Handler -->
        <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
          <Set name="authenticator">
            <New class="org.eclipse.jetty.security.openid.OpenIdAuthenticator">
              <Set name="loginService"><Ref refid="openidLoginService"/></Set>
              <!-- Configure your OpenID provider details (e.g., issuer, client ID) -->
              <Set name="issuer">https://your-openid-provider.com</Set>
              <Set name="clientId">your-client-id</Set>
              <Set name="clientSecret">your-client-secret</Set>
              <Set name="redirectUri">https://your-app.com/openid/callback</Set>
            </New>
          </Set>
          <Set name="loginService"><Ref refid="openidLoginService"/></Set>
          <Call name="addMapping">
            <Arg>/openid/*</Arg>
            <Arg>
              <New class="org.eclipse.jetty.security.ConstraintMapping">
                <Set name="constraint">
                  <New class="org.eclipse.jetty.security.Constraint">
                    <Set name="name">auth</Set>
                    <Set name="roles"><Array type="java.lang.String"><Item>user</Item></Array></Set>
                    <Set name="authenticate">true</Set>
                  </New>
                </Set>
                <Set name="pathSpec">/openid/*</Set>
              </New>
            </Arg>
          </Call>
        </New>

        <!-- FORM Authentication Handler -->
        <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
          <Set name="authenticator">
            <New class="org.eclipse.jetty.security.FormAuthenticator">
              <Set name="loginPage">/form-login.html</Set>
              <Set name="errorPage">/form-error.html</Set>
            </New>
          </Set>
          <Set name="loginService"><Ref refid="localLoginService"/></Set>
          <Call name="addMapping">
            <Arg>/form/*</Arg>
            <Arg>
              <New class="org.eclipse.jetty.security.ConstraintMapping">
                <Set name="constraint">
                  <New class="org.eclipse.jetty.security.Constraint">
                    <Set name="name">auth</Set>
                    <Set name="roles"><Array type="java.lang.String"><Item>user</Item></Array></Set>
                    <Set name="authenticate">true</Set>
                  </New>
                </Set>
                <Set name="pathSpec">/form/*</Set>
              </New>
            </Arg>
          </Call>
        </New>

        <!-- Your Web App Context -->
        <Ref refid="yourWebAppContext"/>
      </Array>
    </Set>
  </New>
</Set>

<!-- Define Login Services -->
<New id="openidLoginService" class="org.eclipse.jetty.security.openid.OpenIdLoginService">
  <Set name="name">OpenIDRealm</Set>
  <!-- Configure user role mapping if needed -->
</New>

<New id="localLoginService" class="org.eclipse.jetty.security.HashLoginService">
  <Set name="name">LocalRealm</Set>
  <Set name="config">etc/realm.properties</Set>
</New>

Step 2: Update web.xml to Match Path Constraints

Add corresponding security constraints to your WEB-INF/web.xml to enforce authentication for each path:

<!-- OpenID Protected Path -->
<security-constraint>
  <web-resource-collection>
    <web-resource-name>OpenID Protected Area</web-resource-name>
    <url-pattern>/openid/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
</security-constraint>

<!-- FORM Protected Path -->
<security-constraint>
  <web-resource-collection>
    <web-resource-name>FORM Protected Area</web-resource-name>
    <url-pattern>/form/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
</security-constraint>

<!-- Login Configurations -->
<login-config>
  <auth-method>OPENID</auth-method>
  <realm-name>OpenIDRealm</realm-name>
</login-config>
<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/form-login.html</form-login-page>
    <form-error-page>/form-error.html</form-error-page>
  </form-login-config>
  <realm-name>LocalRealm</realm-name>
</login-config>

<security-role>
  <role-name>user</role-name>
</security-role>

方案2:自定义登录选择入口

If you want users to pick their authentication method from a single login page (instead of using different URLs), this approach lets you create a unified entry point that redirects to the appropriate auth flow.

Step 1: Create a Login Choice Page

Make a simple HTML page (login-choice.html) that lets users select their login method:

<!DOCTYPE html>
<html>
<head>
  <title>Select Login Method</title>
</head>
<body>
  <h1>Choose Your Login Method</h1>
  <form action="/form-login" method="GET">
    <button type="submit">Login with Local Account</button>
  </form>
  <br>
  <form action="/openid-login" method="GET">
    <button type="submit">Login with OpenID</button>
  </form>
</body>
</html>

Step 2: Configure Context XML for Dual Auth

Update your context XML to include both authenticators, and map the OpenID login endpoint:

<Set name="handler">
  <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
    <Set name="authenticator">
      <!-- Use a delegating authenticator to support multiple methods -->
      <New class="org.eclipse.jetty.security.DelegatingAuthenticator">
        <Set name="authenticators">
          <Array type="org.eclipse.jetty.security.Authenticator">
            <New class="org.eclipse.jetty.security.FormAuthenticator">
              <Set name="loginPage">/login-choice.html</Set>
              <Set name="errorPage">/login-error.html</Set>
            </New>
            <New class="org.eclipse.jetty.security.openid.OpenIdAuthenticator">
              <Set name="loginService"><Ref refid="combinedLoginService"/></Set>
              <!-- Configure OpenID provider details -->
            </New>
          </Array>
        </Set>
      </New>
    </Set>
    <Set name="loginService"><Ref refid="combinedLoginService"/></Set>
    <!-- Map all protected paths -->
    <Call name="addMapping">
      <Arg>/*</Arg>
      <Arg>
        <New class="org.eclipse.jetty.security.ConstraintMapping">
          <Set name="constraint">
            <New class="org.eclipse.jetty.security.Constraint">
              <Set name="name">auth</Set>
              <Set name="roles"><Array type="java.lang.String"><Item>user</Item></Array></Set>
              <Set name="authenticate">true</Set>
            </New>
          </Set>
          <Set name="pathSpec">/*</Set>
          <Set name="excludePaths">
            <Array type="java.lang.String">
              <Item>/login-choice.html</Item>
              <Item>/form-login.html</Item>
              <Item>/openid-login</Item>
            </Array>
          </Set>
        </New>
      </Arg>
    </Call>
  </New>
</Set>

<!-- Combined Login Service (or use separate services if needed) -->
<New id="combinedLoginService" class="org.eclipse.jetty.security.CombinedLoginService">
  <Set name="services">
    <Array type="org.eclipse.jetty.security.LoginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">LocalRealm</Set>
        <Set name="config">etc/realm.properties</Set>
      </New>
      <New class="org.eclipse.jetty.security.openid.OpenIdLoginService">
        <Set name="name">OpenIDRealm</Set>
      </New>
    </Array>
  </Set>
</New>

Step 3: Update web.xml

Set the default login page to your choice page, and ensure all protected paths are covered:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Protected Area</web-resource-name>
    <url-pattern>/*</url-pattern>
    <exclude-url-pattern>/login-choice.html</exclude-url-pattern>
    <exclude-url-pattern>/form-login.html</exclude-url-pattern>
    <exclude-url-pattern>/openid-login</exclude-url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>user</role-name>
  </auth-constraint>
</security-constraint>

<login-config>
  <auth-method>FORM</auth-method>
  <form-login-config>
    <form-login-page>/login-choice.html</form-login-page>
    <form-error-page>/login-error.html</form-error-page>
  </form-login-config>
</login-config>

<security-role>
  <role-name>user</role-name>
</security-role>

Key Notes

  • Activate OpenID Module: Ensure you've already activated Jetty's openid module (you mentioned this is done, but double-check with java -jar start.jar --list-modules).
  • Role Consistency: Make sure both authentication methods assign users to the same role(s) (like user) so they can access the same protected resources.
  • OpenID Provider Setup: For OpenID to work, you'll need to register your app with your chosen provider (e.g., Google, Okta) to get client ID/secret values.

内容的提问来源于stack exchange,提问作者thodoris forreal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 14:28:11