使用Java SDK向MS Teams发消息遇401未授权错误求助
我们尝试使用MS Graph Java SDK向MS Teams发送消息,环境信息如下:
- Java版本:openjdk 17
- microsoft-graph:5.60.0
- azure-identity:1.9.1
已在Azure Active Directory应用注册中配置了委托权限与应用权限,编写的Java代码如下:
final String clientId = "3cb5543544444444a9eb"; final String tenantId = "5435435-235435435435"; // or "common" for multi-tenant apps final String clientSecret = "rewewrewiewrerewrewrz"; final List<String> scopes = Arrays.asList("https://graph.microsoft.com/.default"); final ClientSecretCredential credential = new ClientSecretCredentialBuilder() .clientId(clientId).tenantId(tenantId).clientSecret(clientSecret).build(); if (null == scopes || null == credential) { throw new Exception("Unexpected error"); } final TokenCredentialAuthProvider authProvider = new TokenCredentialAuthProvider( scopes, credential); final GraphServiceClient<okhttp3.Request> graphClient = GraphServiceClient.builder() .authenticationProvider(authProvider).buildClient(); ChatMessage chatMessage = new ChatMessage(); ItemBody body = new ItemBody(); body.content = "Hello World"; chatMessage.body = body; graphClient.teams("4w45234324324fgf4d22-b5e4-94d0").channels("19%0thredfafdafdsfdstajhhgjhg4524554354354cv2").messages() .buildRequest() .post(chatMessage);
运行代码后出现以下错误:
20:30:48.715 [ForkJoinPool.commonPool-worker-1] INFO com.azure.identity.ClientSecretCredential -- Azure Identity => getToken() result for scopes [https://graph.microsoft.com/.default]: SUCCESS Jun 20, 2023 8:30:49 PM com.microsoft.graph.logger.DefaultLogger logError SEVERE: CoreHttpProvider[sendRequestInternal] - 408Graph service exception Jun 20, 2023 8:30:49 PM com.microsoft.graph.logger.DefaultLogger logError SEVERE: Throwable detail: com.microsoft.graph.http.GraphServiceException: Error code: Unauthorized Error message: Message POST is allowed in application-only context only for import purposes. Refer to https://docs.microsoft.com/microsoftteams/platform/graph-api/import-messages/import-external-messages-to-teams for more details. POST https://graph.microsoft.com/v1.0/teams/470b384c-c484-4d22-b5e4-94085c55d1d0/channels/19%3aec755a15c5514be3b630c8613572f132%40thread.tacv2/messages SdkVersion : graph-java/v5.60.0 SdkVersion : graph-java/v5.60.0 [...] 401 : Unauthorized [...]
存在疑问:是否Teams和频道必须处于迁移状态才能通过Java SDK发送消息?另外使用相同密钥和凭证通过Postman调用Teams API可正常工作,不清楚Java代码中缺少什么。
明确API调用模式限制
应用权限模式下,直接调用POST /teams/{team-id}/channels/{channel-id}/messages仅支持导入历史消息,这是Graph API的规则,和Teams/频道是否处于迁移状态无关。如果要发送实时消息,不能用应用权限模式,需切换为委托权限+用户模拟:- 改用
UsernamePasswordCredential替代ClientSecretCredential,传入有Teams频道发送权限的用户账号密码; - 将scopes调整为
ChatMessage.Send等具体委托权限,而非https://graph.microsoft.com/.default。
- 改用
对比Postman与Java代码的逻辑差异
检查Postman使用的认证模式:若Postman用的是用户令牌(委托权限),则和Java代码的应用上下文调用逻辑完全不同,这就是Postman能成功的原因。同时核对Java代码中的Team ID、Channel ID是否与实际一致,注意错误日志中的ID和代码中的参数是否匹配,避免URL编码或拼写错误。验证权限配置有效性
确认应用注册中添加的应用权限已完成管理员同意,仅添加权限未同意会导致401错误。如果确实需要走应用权限导入消息的流程,需确保应用拥有ChannelMessage.Send.All应用权限,且调用时需为消息添加isMessageImport: true等导入相关属性,遵循导入流程规范。
内容的提问来源于stack exchange,提问作者user2315104

