Tomcat自定义JNDIRealm中如何获取Request对象以对接不同LDAP服务器
自定义JNDIRealm获取Request对象及按请求来源切换LDAP服务器实现方案
以下为Tomcat环境下的标准实现方案:
推荐实现方式(适配Tomcat 8.0及以上版本)
Tomcat 8.0+版本的JNDIRealm父类RealmBase已经提供了带Request参数的authenticate重载方法,直接重写该方法即可原生获取Request对象,无需额外适配:
import org.apache.catalina.connector.Request; import org.apache.catalina.realm.JNDIRealm; import javax.servlet.http.HttpServletResponse; import java.security.Principal; public class CustomRouteLdapRealm extends JNDIRealm { // 内网普通LDAP服务器地址 private String innerLdapUrl; // 外网双因子LDAP服务器地址 private String outerLdapUrl; @Override public Principal authenticate(Request request, HttpServletResponse response) { // 直接从Request对象获取客户端IP判断网络来源 String clientIp = request.getRemoteAddr(); boolean isInnerAccess = checkInnerNetwork(clientIp); // 高并发场景建议不要直接修改全局connectionURL成员变量,避免线程安全问题 // 推荐重写getDirectoryContext()方法,根据当前网络标识动态创建对应LDAP的上下文 if (isInnerAccess) { setConnectionURL(innerLdapUrl); } else { setConnectionURL(outerLdapUrl); } // 复用父类原有JNDI认证逻辑 return super.authenticate(request, response); } /** * 自定义内网IP判断逻辑,可根据实际网段调整 */ private boolean checkInnerNetwork(String clientIp) { return clientIp.startsWith("10.") || clientIp.startsWith("192.168.") || clientIp.matches("172\\.(1[6-9]|2[0-9]|3[01])\\..*"); } // 配置参数注入方法,供server.xml配置调用 public void setInnerLdapUrl(String innerLdapUrl) { this.innerLdapUrl = innerLdapUrl; } public void setOuterLdapUrl(String outerLdapUrl) { this.outerLdapUrl = outerLdapUrl; } }
低版本Tomcat兼容方案(适配Tomcat 7及以下版本)
如果使用的Tomcat版本没有带Request参数的authenticate重载方法,可通过自定义Valve传递Request:
- 实现自定义Valve,在
invoke方法中将当前Request存入ThreadLocal<Request> - 在自定义JNDIRealm的认证逻辑中从ThreadLocal取出Request对象
- 请求处理完成后必须手动清除ThreadLocal,避免内存泄漏
部署配置
将编译好的自定义Realm的jar包放入Tomcatlib/目录,修改server.xml中的Realm配置即可:
<Realm className="com.yourpackage.CustomRouteLdapRealm" innerLdapUrl="ldap://内网LDAP地址:389" outerLdapUrl="ldap://外网双因子LDAP地址:389" <!-- 保留原有JNDIRealm的其他配置项,如connectionName、userSearch、userPattern等 --> />
注意:高并发场景下直接修改
connectionURL成员变量存在线程安全问题,建议重写getDirectoryContext()方法,根据当前请求的网络属性动态创建对应LDAP服务器的上下文,不要修改全局配置变量。
内容的提问来源于stack exchange,提问作者zackhalil
相关产品推荐
相关产品推荐

