Java Play框架集成Microsoft Teams发消息遇CSRF问题求助
Play框架API集成Microsoft Teams的CSRF错误解决及代码示例
一、CSRF校验错误的解决方案
Play框架默认启用了CSRF过滤器,你的/sendNotification接口属于第三方调用的API接口,不需要CSRF保护,可通过以下两种方式跳过校验:
方式1:在Controller方法上添加注解
在sendNotification方法上添加@NoCSRFCheck注解,直接跳过该接口的CSRF校验:
import play.filters.csrf.NoCSRFCheck; // ... 其他代码 @NoCSRFCheck public CompletionStage<Result> sendNotification(Http.Request request) { // 原有方法逻辑 }
方式2:在路由文件中配置跳过
在conf/routes文件里,给对应路由添加nocsrf标记:
POST /sendNotification controllers.TeamsNotificationController.sendNotification(request: Request) nocsrf
二、Microsoft Teams消息发送完整代码示例
1. 模型类 TeamsNotification
package models; public class TeamsNotification { private String webhookUrl; private String message; // Jackson序列化/反序列化需要无参构造 public TeamsNotification() {} public TeamsNotification(String webhookUrl, String message) { this.webhookUrl = webhookUrl; this.message = message; } // Getter和Setter方法 public String getWebhookUrl() { return webhookUrl; } public void setWebhookUrl(String webhookUrl) { this.webhookUrl = webhookUrl; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
2. 服务类 TeamsNotificationService
使用Play的WSClient发送HTTP请求到Teams Webhook:
package services; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import models.TeamsNotification; import play.libs.ws.WSClient; import javax.inject.Inject; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletionStage; public class TeamsNotificationService { private final WSClient wsClient; private final ObjectMapper objectMapper; @Inject public TeamsNotificationService(WSClient wsClient, ObjectMapper objectMapper) { this.wsClient = wsClient; this.objectMapper = objectMapper; } public CompletionStage<JsonNode> sendNotification(TeamsNotification notification) { // 构造Teams接受的简单文本消息 payload Map<String, String> payload = new HashMap<>(); payload.put("text", notification.getMessage()); return wsClient.url(notification.getWebhookUrl()) .setContentType("application/json") .post(payload) .thenApply(response -> { Map<String, String> result = new HashMap<>(); if (response.getStatus() == 200) { result.put("status", "success"); result.put("message", "消息已成功发送到Teams"); } else { result.put("status", "failed"); result.put("message", "发送失败,响应状态码:" + response.getStatus()); } return objectMapper.valueToTree(result); }) .exceptionally(e -> { Map<String, String> errorResult = new HashMap<>(); errorResult.put("status", "failed"); errorResult.put("message", "发送过程出错:" + e.getMessage()); return objectMapper.valueToTree(errorResult); }); } }
3. 复杂消息示例(Adaptive Card)
如果需要发送更美观的结构化消息,可使用Teams的Adaptive Card格式,修改服务类中的payload构造部分:
// 替换原payload构造代码为以下内容 String adaptiveCardPayload = """ { "type": "message", "attachments": [ { "contentType": "application/vnd.microsoft.card.adaptive", "content": { "type": "AdaptiveCard", "version": "1.0", "body": [ { "type": "TextBlock", "text": "%s", "size": "large", "weight": "bolder" }, { "type": "TextBlock", "text": "来自Play框架API的通知", "size": "small", "color": "secondary" } ] } } ] } """.formatted(notification.getMessage()); // 发送请求时使用该字符串作为请求体 return wsClient.url(notification.getWebhookUrl()) .setContentType("application/json") .post(adaptiveCardPayload) // 后续响应处理逻辑和之前一致
内容的提问来源于stack exchange,提问作者Anish
相关产品推荐
相关产品推荐

