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

Struts 2环境下拦截Tomcat的j_security_check并修改LDAP认证前用户名的最优实现方案咨询

最优方案选择与实现建议

针对你的需求,Servlet Filter(过滤器)是最优实现方式,原因和具体实现细节如下:

三种方案的对比分析

  • JavaScript前端修改:实现简单(比如在表单提交前修改j_username的值),但完全不安全——用户可以禁用JavaScript、通过浏览器开发者工具篡改请求参数,直接提交原始用户名绕开前端处理,因此只能作为辅助优化,不能作为核心认证前的修改手段。
  • Struts 2 Interceptor(拦截器):不可行,因为j_security_check是Servlet容器(比如Tomcat)提供的内置认证端点,不属于Struts 2的Action请求范畴,不会进入Struts的拦截器链,拦截器根本捕获不到这个请求。
  • Servlet Filter:完美匹配需求,Filter工作在Servlet容器的请求处理流程最前端,能在容器处理j_security_check认证逻辑之前拦截请求并修改参数,而且后端处理无法被前端绕过,安全性和可靠性都有保障。

如何让登录请求先经过Filter再到j_security_check

完全可以实现,只需要在web.xml中配置Filter,并将其映射到/j_security_check路径即可,具体步骤:

1. 编写自定义Filter类

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.stream.Collectors;

public class UsernameModifyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化逻辑(若有需要可添加)
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        // 包装请求,实现j_username参数修改
        HttpServletRequestWrapper modifiedRequest = new HttpServletRequestWrapper(httpRequest) {
            @Override
            public String getParameter(String name) {
                if ("j_username".equals(name)) {
                    String originalUsername = super.getParameter(name);
                    if (originalUsername != null) {
                        // 这里替换为你的用户名修改逻辑,比如移除指定字符
                        return originalUsername.replaceAll("[@#$]", ""); // 示例:移除@、#、$字符
                    }
                }
                return super.getParameter(name);
            }

            @Override
            public Map<String, String[]> getParameterMap() {
                Map<String, String[]> originalMap = super.getParameterMap();
                if (originalMap.containsKey("j_username")) {
                    String[] originalValues = originalMap.get("j_username");
                    String[] modifiedValues = new String[originalValues.length];
                    for (int i = 0; i < originalValues.length; i++) {
                        modifiedValues[i] = originalValues[i].replaceAll("[@#$]", "");
                    }
                    // 返回修改后的参数Map
                    return Collections.unmodifiableMap(
                            originalMap.entrySet().stream()
                                    .map(entry -> {
                                        if ("j_username".equals(entry.getKey())) {
                                            return Map.entry(entry.getKey(), modifiedValues);
                                        }
                                        return entry;
                                    })
                                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
                    );
                }
                return originalMap;
            }

            @Override
            public Enumeration<String> getParameterNames() {
                return super.getParameterNames();
            }

            @Override
            public String[] getParameterValues(String name) {
                if ("j_username".equals(name)) {
                    String[] originalValues = super.getParameterValues(name);
                    if (originalValues != null) {
                        String[] modifiedValues = new String[originalValues.length];
                        for (int i = 0; i < originalValues.length; i++) {
                            modifiedValues[i] = originalValues[i].replaceAll("[@#$]", "");
                        }
                        return modifiedValues;
                    }
                }
                return super.getParameterValues(name);
            }
        };

        // 将修改后的请求传递给下一个处理环节(最终到j_security_check)
        chain.doFilter(modifiedRequest, response);
    }

    @Override
    public void destroy() {
        // 销毁逻辑(若有需要可添加)
    }
}

2. 在web.xml中配置Filter

在现有配置中添加Filter定义和映射(位置可在login-config前后):

<filter>
    <filter-name>UsernameModifyFilter</filter-name>
    <filter-class>com.yourpackage.UsernameModifyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>UsernameModifyFilter</filter-name>
    <url-pattern>/j_security_check</url-pattern>
</filter-mapping>

这样所有提交到/j_security_check的请求都会先经过这个Filter,修改j_username参数后,再传递给容器的JNDIRealm LDAP认证逻辑。

补充说明

  • 如果你关注前端用户体验,可以同时保留JavaScript修改(比如表单提交时先修改一次),但必须以Filter的后端修改作为最终保障,防止恶意绕过。
  • 注意调整修改逻辑,确保修改后的用户名与LDAP端的用户条目规则匹配,避免认证失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 20:53:15