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
相关产品推荐
相关产品推荐

