You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 20:23:17