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

React应用实现Microsoft单点登录后,如何对接Node.js后端同步身份?

React + Node/Express 同步Azure AD登录及Graph API邮件发送实现

针对你已完成React端MSAL单点登录,需同步Node后端身份以调用Microsoft Graph API发送邮件的需求,以下是落地步骤:

一、Azure AD应用注册调整

  • 在现有应用注册中添加Web平台,配置后端重定向URI(示例:http://localhost:3001/auth/callback)
  • 启用授权码流:勾选"授权代码"和"ID令牌"选项
  • 添加Graph API委托权限:Mail.Send,并完成管理员授权(租户内应用需此步骤)

二、React前端修改:传递授权码到后端

前端已基于@azure/msal-browser/@azure/msal-react实现登录,需调整为授权码流并将授权码传给后端:

  1. 调整MSAL配置为授权码流:
const msalConfig = {
  auth: {
    clientId: "你的客户端ID",
    authority: "https://login.microsoftonline.com/你的租户ID",
    redirectUri: "http://localhost:3000", // 前端原有重定向URI
    responseType: "code" // 切换为授权码流
  }
};
  1. 登录成功后获取授权码并调用后端接口:
// 登录成功回调或组件逻辑中
const handleLoginSuccess = (response) => {
  const authCode = response.code;
  fetch("http://localhost:3001/auth/exchange-code", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ code: authCode })
  })
  .then(res => res.json())
  .then(data => {
    // 可将后端返回的会话标识存到localStorage或状态管理中
    localStorage.setItem("userSession", JSON.stringify(data));
  })
  .catch(err => console.error("授权码传递失败:", err));
};

三、Node/Express后端实现

使用@azure/msal-node处理授权码兑换令牌,并调用Graph API发送邮件:

  1. 安装依赖:
npm install @azure/msal-node express cors
  1. 核心代码实现:
const express = require("express");
const cors = require("cors");
const { ConfidentialClientApplication } = require("@azure/msal-node");
const app = express();

app.use(cors());
app.use(express.json());

// MSAL客户端配置
const msalConfig = {
  auth: {
    clientId: "你的客户端ID",
    authority: "https://login.microsoftonline.com/你的租户ID",
    clientSecret: "你的客户端密钥" // 从Azure应用注册的"证书和密码"中获取
  }
};

const cca = new ConfidentialClientApplication(msalConfig);
const REDIRECT_URI = "http://localhost:3001/auth/callback"; // 与Azure配置一致
const GRAPH_SCOPES = ["Mail.Send"];

// 兑换授权码为Graph API访问令牌
app.post("/auth/exchange-code", async (req, res) => {
  const { code } = req.body;
  try {
    const tokenRequest = {
      code,
      redirectUri: REDIRECT_URI,
      scopes: GRAPH_SCOPES
    };
    const tokenResponse = await cca.acquireTokenByCode(tokenRequest);
    // 生产环境建议用express-session存储令牌,而非直接返回给前端
    res.json({ 
      accessToken: tokenResponse.accessToken, 
      accountInfo: tokenResponse.account 
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// 调用Graph API发送邮件接口
app.post("/api/send-email", async (req, res) => {
  const { accessToken, toEmail, subject, content } = req.body;
  try {
    const graphRes = await fetch("https://graph.microsoft.com/v1.0/me/sendMail", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${accessToken}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        message: {
          subject,
          body: {
            contentType: "Text",
            content
          },
          toRecipients: [{ emailAddress: { address: toEmail } }]
        },
        saveToSentItems: true
      })
    });

    if (graphRes.ok) {
      res.json({ success: true, msg: "邮件发送成功" });
    } else {
      const graphErr = await graphRes.json();
      res.status(400).json({ success: false, error: graphErr });
    }
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});

app.listen(3001, () => console.log("后端服务运行于 http://localhost:3001"));

四、核心注意事项

  • 前端与后端的clientId、tenantId必须完全一致,后端clientSecret需从Azure应用注册的"证书和密码"生成
  • 授权码仅能使用一次,后端兑换令牌后即失效
  • 生产环境必须使用HTTPS传输,避免令牌泄露
  • 敏感令牌建议存储在后端会话中(如express-session+Redis),不要直接返回给前端长期存储

内容的提问来源于stack exchange,提问作者dmikester1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:35:31