使用ADAL4J通过用户名密码获取Token时遇SAXParseException求助
解决ADAL4J获取微软Token时的SAXParseException(DOCTYPE被禁止)问题
嘿,我看你在用ADAL4J的用户名密码流获取微软身份验证Token时碰到了SAXParseException,核心错误是DOCTYPE is disallowed when the feature "http://apache.org/xml/features/disallow-doctype-decl" set to true。这个问题其实是ADAL4J解析微软元数据响应时的配置冲突导致的,下面给你一步步排查和解决:
1. 先升级ADAL4J版本(最稳妥的方案)
旧版本的ADAL4J在XML解析的安全配置上有小问题,后续版本已经修复了对DOCTYPE声明的兼容处理。建议你把ADAL4J的依赖升级到1.6.7及以上的稳定版。比如用Maven的话,修改依赖:
<dependency> <groupId>com.microsoft.azure</groupId> <artifactId>adal4j</artifactId> <version>1.6.7</version> </dependency>
升级后大部分情况下这个错误会直接消失,因为新版本调整了解析器的特性配置。
2. 检查你代码里的资源URI是否正确
我注意到你代码里写的是"<resource>",这是HTML转义后的占位符,实际运行时必须替换成真实的目标资源URI,比如:
- 调用微软Graph API就用
https://graph.microsoft.com - 调用Azure AD Graph API用
https://graph.windows.net - 或者你自己的自定义API的资源ID
如果资源URI不对,可能返回的元数据响应格式异常,间接触发解析错误。修正后的代码片段参考:
// 初始化认证上下文 AuthenticationContext context = new AuthenticationContext("https://login.microsoftonline.com/common/", false, service); // 替换成真实的资源URI、客户端ID、用户名和密码 Future<AuthenticationResult> future = context.acquireToken( "https://graph.microsoft.com", "your-client-id-here", "user@your-domain.com", "user-password-here", null ); AuthenticationResult result = future.get(); // 输出Token信息 System.out.println("Access Token - " + result.getAccessToken()); System.out.println("Refresh Token - " + result.getRefreshToken()); System.out.println("ID Token - " + result.getIdToken());
3. 若无法升级版本,试试自定义XML解析配置(应急方案)
如果因为项目依赖限制没法升级ADAL4J,可以通过反射修改MexParser里的XML解析器配置,关闭禁止DOCTYPE的特性。不过这种方式比较“hack”,仅建议应急使用:
// 在调用acquireToken之前执行这段代码 try { // 反射获取MexParser类 Class<?> mexParserClass = Class.forName("com.microsoft.aad.adal4j.MexParser"); // 获取getPolicy方法并设置可访问 Method getPolicyMethod = mexParserClass.getDeclaredMethod("getPolicy", Document.class); getPolicyMethod.setAccessible(true); // 配置DocumentBuilderFactory,关闭disallow-doctype-decl特性 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); // 这里需要替换MexParser内部使用的DocumentBuilderFactory,可能需要更复杂的反射操作 // 注意:不同ADAL4J版本的内部实现可能不同,这个方法不一定通用 } catch (Exception e) { e.printStackTrace(); }
额外提醒
- 确保你的Azure AD应用已经开启了资源所有者密码凭据流(ROPC),因为你用的是用户名密码方式获取Token,这个流需要在应用注册的“认证”页面里开启对应的权限。
- 尽量避免使用ROPC流,微软更推荐用授权码流或设备码流,ROPC的安全性相对较低,仅适用于特定的 legacy 场景。
内容的提问来源于stack exchange,提问作者user2788875
相关产品推荐
相关产品推荐

