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

Kotlin Spring Boot中实现Azure Graph API OAuth2令牌自动刷新与持久化

解决方案:持久化OAuth2令牌实现自动刷新(Kotlin Spring Boot)

核心思路

借助Microsoft Graph SDK的令牌缓存扩展能力,将访问令牌、刷新令牌等缓存数据持久化到数据库,重启应用时自动读取缓存完成令牌刷新,无需重复手动认证。

最小改动步骤

1. 定义令牌存储实体(JPA示例)

创建数据库实体类,用于存储令牌缓存的完整数据:

import jakarta.persistence.*

@Entity
@Table(name = "oauth2_token_cache")
class OAuth2TokenCache(
    @Id
    @Column(unique = true)
    val userId: String, // 固定为目标邮箱support@ourcompany.com.au
    @Column(length = 2000)
    val cacheContent: String, // SDK生成的完整令牌缓存JSON
    val lastUpdated: Long = System.currentTimeMillis()
)

2. 实现自定义令牌缓存序列化器

对接数据库操作,实现SDK要求的ITokenCacheSerializer接口:

import com.microsoft.graph.authentication.ITokenCacheSerializer
import org.springframework.stereotype.Component
import javax.persistence.EntityManager

@Component
class DatabaseTokenCache(
    private val entityManager: EntityManager,
    private val targetUserId: String = "support@ourcompany.com.au"
) : ITokenCacheSerializer {

    override fun serialize(tokenCache: String) {
        val existingCache = entityManager.find(OAuth2TokenCache::class.java, targetUserId)
            ?: OAuth2TokenCache(userId = targetUserId, cacheContent = tokenCache)
        existingCache.cacheContent = tokenCache
        existingCache.lastUpdated = System.currentTimeMillis()
        entityManager.merge(existingCache)
    }

    override fun deserialize(): String? {
        return entityManager.find(OAuth2TokenCache::class.java, targetUserId)?.cacheContent
    }
}

3. 修改原有认证代码,注入自定义缓存

在设备码流认证逻辑中,配置使用数据库缓存替换默认文件缓存:

import com.microsoft.graph.authentication.DeviceCodeCredentialBuilder
import com.microsoft.graph.authentication.TokenCachePersistenceOptions
import com.microsoft.graph.requests.GraphServiceClient
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service

@Service
class GraphAuthService(
    @Autowired
    private val dbTokenCache: DatabaseTokenCache
) {
    fun getAuthenticatedClient(): GraphServiceClient<*> {
        val cacheOptions = TokenCachePersistenceOptions().apply {
            isEnablePersistence = true
            serializer = dbTokenCache
        }

        val credential = DeviceCodeCredentialBuilder()
            .clientId("your-client-id") // 替换为你的Azure AD客户端ID
            .tenantId("your-tenant-id") // 替换为你的租户ID
            .deviceCodeCallback { codeInfo ->
                // 仅首次认证时触发,后续自动刷新不会执行此逻辑
                println("请访问 ${codeInfo.verificationUri} 输入代码: ${codeInfo.userCode}")
            }
            .tokenCachePersistenceOptions(cacheOptions)
            .build()

        return GraphServiceClient.builder()
            .authenticationProvider(credential)
            .buildClient()
    }
}

4. 验证自动刷新逻辑

  • 首次启动:控制台会输出设备码提示,手动完成认证后,令牌缓存会自动写入数据库
  • 后续重启:SDK会自动读取数据库中的缓存,若令牌未过期直接使用;若已过期则自动调用刷新令牌获取新凭证,全程无需人工干预

关键注意事项

  • 开启Spring JPA自动建表(spring.jpa.hibernate.ddl-auto=update),确保oauth2_token_cache表自动生成
  • 确保Azure AD应用已配置Mail.Read等必要权限,且已完成管理员同意
  • 令牌缓存的JSON结构由SDK维护,直接存储完整字符串可避免解析错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:42:34