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

如何在Spring Boot中为微软工作账户实现Outlook日历同步鉴权?

在Spring Boot中实现Outlook日历同步的鉴权流程(获取Access/Refresh Token)

一、Azure AD应用注册(前置步骤)

  • 登录Azure门户,注册新的"应用注册":
    • 账户类型选择"任何组织目录中的账户和个人Microsoft账户"(覆盖Outlook个人用户)
    • 设置重定向URI:选择"Web"类型,填入你的应用回调地址,比如http://localhost:8080/outlook/callback
  • 配置API权限:
    • 点击"API权限" -> "添加权限" -> 选择"Microsoft Graph" -> "委托权限"
    • 搜索并勾选Calendars.ReadWrite(用于读写日历)和offline_access(用于获取Refresh Token)
    • 个人账户用户授权时自行确认,企业账户需管理员同意
  • 开启授权代码流:
    • 进入"认证" -> "高级设置",确保"授权代码流"已勾选(默认通常开启)
  • 记录应用的客户端ID和客户端密钥(在"证书和密码"中生成客户端密钥)

二、Spring Boot项目配置

1. 添加依赖

在pom.xml中加入以下依赖:

<!-- Spring OAuth2 Client -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- Microsoft Graph SDK -->
<dependency>
    <groupId>com.microsoft.graph</groupId>
    <artifactId>microsoft-graph</artifactId>
    <version>6.3.0</version>
</dependency>

2. 配置OAuth2客户端

在application.yml中添加配置:

spring:
  security:
    oauth2:
      client:
        registration:
          microsoft:
            client-id: 你的Azure应用客户端ID
            client-secret: 你的Azure应用客户端密钥
            scope: Calendars.ReadWrite, offline_access
            redirect-uri: "{baseUrl}/outlook/callback"
            authorization-grant-type: authorization_code
        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

三、构建鉴权API(独立于现有登录流程)

1. Security配置

调整Spring Security,确保仅已登录(通过你的现有方案)的用户能访问Outlook鉴权接口:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/outlook/**").authenticated()
                        .anyRequest().permitAll()
                )
                .oauth2Client(Customizer.withDefaults());
        return http.build();
    }
}

2. 鉴权Controller实现

创建处理授权引导和回调的接口,将Token与现有用户关联存储:

@RestController
@RequestMapping("/outlook")
public class OutlookAuthController {

    private final OAuth2AuthorizedClientService authorizedClientService;
    private final OAuth2AuthorizationRequestResolver authorizationRequestResolver;

    public OutlookAuthController(OAuth2AuthorizedClientService authorizedClientService,
                                 OAuth2AuthorizationRequestResolver authorizationRequestResolver) {
        this.authorizedClientService = authorizedClientService;
        this.authorizationRequestResolver = authorizationRequestResolver;
    }

    // 引导用户跳转到Outlook授权页面
    @GetMapping("/authorize")
    public RedirectView authorize(HttpServletRequest request, @RequestParam String userId) {
        OAuth2AuthorizationRequest authRequest = authorizationRequestResolver.resolve(request, "microsoft");
        return new RedirectView(authRequest.getAuthorizationUri());
    }

    // 处理Outlook授权回调,获取Token
    @GetMapping("/callback")
    public ResponseEntity<String> callback(HttpServletRequest request,
                                           @RequestParam String code,
                                           @RequestParam String state) {
        // 替换为你的现有登录逻辑获取用户ID
        String userId = (String) request.getSession().getAttribute("userId");
        
        OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient("microsoft", userId);
        OAuth2AccessTokenResponse tokenResponse = authorizedClient.getAccessTokenResponse();
        
        String accessToken = tokenResponse.getAccessToken().getTokenValue();
        String refreshToken = tokenResponse.getRefreshToken().getTokenValue();
        
        // 替换为你的实际存储逻辑,将Token与用户绑定
        saveTokensToDatabase(userId, accessToken, refreshToken);
        
        return ResponseEntity.ok("Outlook授权成功,Token已保存");
    }

    private void saveTokensToDatabase(String userId, String accessToken, String refreshToken) {
        // 示例:写入用户表的对应字段
    }
}

四、关键注意事项

  • 必须包含offline_access scope:只有添加这个权限,才能获取Refresh Token,避免Access Token过期后需用户重新授权。
  • Token与用户绑定:每个用户的Token独立,必须关联你的应用内用户ID,防止混淆。
  • Refresh Token续期:当Access Token过期时,调用Azure的Token接口,用Refresh Token换取新的Access Token。
  • MS Graph API调用示例:
    GraphServiceClient graphClient = GraphServiceClient.builder()
            .authenticationProvider(request -> {
                request.addHeader("Authorization", "Bearer " + accessToken);
                return CompletableFuture.completedFuture(null);
            })
            .buildClient();
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:10:35