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

求助:基于Microsoft Graph API构建多租户Java OAuth2.0客户端

多租户Microsoft Graph Java客户端实现指南(支持全MS身份类型)

一、Azure AD应用注册核心配置(多租户关键)

  • 注册应用时,账号类型必须选「任何组织目录中的账户和个人Microsoft账户(例如Skype、Xbox)」,这是让应用兼容工作/学校账户+个人账户的核心前提。
  • 配置重定向URI:选「Web」类型,填你的Java应用回调地址(比如http://localhost:8080/login/oauth2/code/microsoft)。
  • 添加委派权限:
    • 必须加的:Calendars.Read(读取日历)、offline_access(获取刷新令牌,维持长期访问)、User.Read(基础用户信息);如果需要修改日历就加Calendars.ReadWrite。
    • 注意:部分高权限需要租户管理员同意,普通权限用户自行同意即可。
  • 生成并保存客户端密钥:在「证书和密码」页面创建客户端密码,务必记录好密码值(只显示一次)。

二、Java项目依赖配置(Maven示例)

直接把以下依赖加到pom.xml里,用最新稳定版即可:

<dependencies>
    <!-- Microsoft Graph SDK核心 -->
    <dependency>
        <groupId>com.microsoft.graph</groupId>
        <artifactId>microsoft-graph</artifactId>
        <version>6.3.0</version>
    </dependency>
    <!-- Azure身份验证工具 -->
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-identity</artifactId>
        <version>1.12.0</version>
    </dependency>
    <!-- 如果用Spring Boot,加这个简化OAuth2流程 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>

三、Authorization Code Flow 多租户适配实现

1. Spring Boot OAuth2客户端配置

在application.yml里配置多租户相关端点,核心是用common代替特定租户ID:

spring:
  security:
    oauth2:
      client:
        registration:
          microsoft:
            client-id: 你的应用ID
            client-secret: 你的客户端密钥
            scope: Calendars.Read, offline_access, User.Read
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          microsoft:
            authorization-uri: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
            token-uri: https://login.microsoftonline.com/common/oauth2/v2.0/token
            user-info-uri: https://graph.microsoft.com/v1.0/me
            user-name-attribute: id

common端点是关键,它能接受所有类型的MS身份登录。

2. 构建GraphClient实例

从OAuth2回调中拿到授权码后,用Azure Identity构建凭证,再创建Graph客户端:

import com.microsoft.graph.requests.extensions.GraphServiceClient;
import com.azure.identity.AuthorizationCodeCredential;
import com.azure.identity.AuthorizationCodeCredentialBuilder;
import okhttp3.Request;

// 从回调请求中获取授权码
String authCode = 回调请求中的授权码参数;
String redirectUri = "http://localhost:8080/login/oauth2/code/microsoft";

// 构建多租户凭证
AuthorizationCodeCredential credential = new AuthorizationCodeCredentialBuilder()
        .clientId("你的应用ID")
        .clientSecret("你的客户端密钥")
        .authorizationCode(authCode)
        .redirectUrl(redirectUri)
        .tenantId("common")
        .build();

// 创建Graph服务客户端
GraphServiceClient<Request> graphClient = GraphServiceClient.builder()
        .authenticationProvider(request -> {
            String accessToken = credential.getToken().block().getToken();
            request.addHeader("Authorization", "Bearer " + accessToken);
            return request;
        })
        .buildClient();

四、获取用户日历数据

直接调用Graph API拉取日历事件:

import com.microsoft.graph.models.extensions.Event;
import com.microsoft.graph.requests.extensions.IGraphServiceEventsCollectionPage;

// 获取当前用户的日历事件,可按需添加筛选、排序
IGraphServiceEventsCollectionPage events = graphClient.me().events()
        .buildRequest()
        .select("subject,start,end,location")
        .get();

// 遍历所有事件(含分页)
while (events != null) {
    for (Event event : events.getCurrentPage()) {
        System.out.println("事件主题: " + event.subject);
        System.out.println("开始时间: " + event.start.dateTime);
        System.out.println("结束时间: " + event.end.dateTime);
    }
    events = events.getNextPage() != null ? events.getNextPage().get() : null;
}

五、订阅日历新增事件通知

要接收通知,你的回调端点必须是HTTPS(本地测试可以用ngrok暴露HTTPS地址):

1. 创建订阅

import com.microsoft.graph.models.extensions.Subscription;
import java.time.OffsetDateTime;

Subscription subscription = new Subscription();
subscription.changeType = "created"; // 只监听新增事件
subscription.notificationUrl = "https://你的HTTPS端点/webhook/microsoft";
subscription.resource = "/me/events";
subscription.expirationDateTimeOffset = OffsetDateTime.now().plusDays(3); // 订阅最长3天,到期需续期
subscription.clientState = "随机加密字符串"; // 用于验证通知真实性

Subscription createdSub = graphClient.subscriptions()
        .buildRequest()
        .post(subscription);

// 保存订阅ID和clientState,后续验证和续期要用
System.out.println("订阅ID: " + createdSub.id);

2. 完成订阅验证

微软会在创建订阅时发送验证请求到你的端点,直接返回验证令牌即可:

// Spring控制器示例
@PostMapping("/webhook/microsoft")
public ResponseEntity<String> verifySubscription(@RequestParam("validationToken") String validationToken) {
    return ResponseEntity.ok(validationToken);
}

3. 处理事件通知

当有新事件添加时,微软会POST通知到你的端点,解析并处理:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;

@PostMapping("/webhook/microsoft")
public ResponseEntity<Void> handleCalendarNotification(@RequestBody String payload) {
    ObjectMapper mapper = new ObjectMapper();
    try {
        JsonNode root = mapper.readTree(payload);
        String receivedClientState = root.get("value").get(0).get("clientState").asText();
        // 验证clientState是否和创建订阅时一致,防止伪造通知
        if (!receivedClientState.equals("你设置的随机字符串")) {
            return ResponseEntity.badRequest().build();
        }
        // 从通知中拿到事件资源地址,调用API获取详情
        String eventUrl = root.get("value").get(0).get("resource").asText();
        Event newEvent = graphClient.customRequest(eventUrl, Event.class)
                .buildRequest()
                .get();
        // 这里写你的业务处理逻辑
        System.out.println("新增日历事件: " + newEvent.subject);
    } catch (Exception e) {
        e.printStackTrace();
        return ResponseEntity.badRequest().build();
    }
    return ResponseEntity.ok().build();
}

六、多租户常见注意事项

  • 权限同意:工作/学校账户的部分高权限需要租户管理员批准,个人账户用户可自行同意。
  • 令牌续期:借助offline_access权限获取的刷新令牌,在访问令牌过期时自动获取新令牌,维持会话。
  • 本地测试:必须用HTTPS端点接收通知,ngrok是最方便的本地测试工具。
  • 订阅续期:订阅最长有效期3天,需要定时续期才能持续接收通知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:50:24