最近项目,需要Kafka基于GSSAPI认证模式,进行安全认证。然后通过Kafka官网文档等资料,完成认证操作。
但是一个比较诡异的事是,代码在本地环境上,能够成功运行,但是基于Docker进行部署时,出现如下异常。
在这里插入图片描述
后续,通过排查,发现Docker容器内,该文件存在,拥有对应的操作权限,且配置内容也是正确的。
无奈之下,通读一遍JaasContext.defaultContext方法。发现该异常信息,来源于configEntities属性判断处。
在这里插入图片描述
最后发现,configEntities属性,通过

jaasConfig.getAppConfigurationEntry(globalContextName)

获取,而globalContextName对应于KafkaClient字符串常量。
进入到该方法
在这里插入图片描述
在这里插入图片描述
到目前为止,基本上知道了configEntities局部变量,最终通过ConfigFile类的spi属性获取。而spi属性获取方式,是通过其内部的configuration属性获取到的。
在这里插入图片描述
到这里,想必各位比较好奇,ConfigFile中spi属性中configuration属性,究竟存储的是什么属性呢?
下面,让我们通过如下代码,来查看configuration属性值。

Configuration jaasConfig = Configuration.getConfiguration();

		for (Field field : jaasConfig.getClass().getDeclaredFields()) {
			if ("spi".equals(field.getName())) {
				field.setAccessible(true);
				Field modifiersField = Field.class.getDeclaredField("modifiers");
				modifiersField.setAccessible(true); // Field 的 modifiers 是私有的
				modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

				field.setAccessible(true);
				Object spi = field.get(jaasConfig);

				for (Field spiField : spi.getClass().getDeclaredFields()) {
					if ("configuration".equals(spiField.getName())) {
						spiField.setAccessible(true);
						return JSONObject.toJSONString(spiField.get(spi));
					}
				}
			}
		}

在创建消费者之前,运行这段代码,发现结果竟然是空的。
想必各位一定好奇,明明文件是存在的,为什么没有把文件内容给读取出来呢?无奈之下,通过idea远程连接Docker环境,查看其内部运行过程。结果大吃一惊,这种操作方式,configuration属性又有值了。
认证观察一下代码后,发现,spi属性,是在ConfigFile构造方法处,进行的初始化。而configuration属性加载,也是在Spi的构造方法,通过init方法,完成的初始化。
在这里插入图片描述
在这里插入图片描述
而代码处用于设置java.security.auth.login.config环境变量的代码,却在创建消费者处,进行的初始化。
也就是说,ConfigFile完成java.security.auth.login.config属性,加载文件内容之后,代码侧,才开始设置java.security.auth.login.config属性。
这也就解释了,为什么通过反射获取configuration属性值,会为空。
既然,原因找到了,那么怎么解决问题呢?
其实看到这里,这个异常的解决方法,很简单,在环境启动前,设置java.security.auth.login.config属性。
在这里插入图片描述
到此,整个异常解决。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐