MSAL4j使用授权码流时如何将令牌缓存持久化到数据库
MSAL4j 授权码流令牌缓存数据库持久化实现方案
MSAL4j 内置了自定义缓存的扩展接口ITokenCacheAccessAspect,不需要修改原有令牌获取逻辑,仅需实现该接口绑定到客户端实例即可实现数据库持久化。
1. 准备数据库存储结构
你需要先创建一张令牌缓存表,核心字段参考:
- 主键ID
user_home_account_id:MSAL返回的用户全局唯一标识,作为查询keycache_content:序列化后的令牌缓存字符串created_at/updated_at:记录创建/更新时间expire_at:缓存过期时间,可按Azure AD refresh_token最长有效期(默认90天)设置
2. 实现自定义缓存访问切面
实现ITokenCacheAccessAspect接口,完成缓存的读库、写库逻辑:
import com.microsoft.aad.msal4j.ITokenCacheAccessAspect; import com.microsoft.aad.msal4j.ITokenCacheAccessContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; // 示例基于Spring,非Spring环境可自行初始化实例 @Component public class DbTokenCacheAspect implements ITokenCacheAccessAspect { // 自行实现的数据库操作DAO,对应你创建的缓存表 @Autowired private TokenCacheDao tokenCacheDao; @Override public void beforeCacheAccess(ITokenCacheAccessContext cacheContext) { // 获取当前用户的唯一标识 String userAccountId = cacheContext.account().homeAccountId(); // 从数据库查询对应用户的缓存 TokenCachePo cachePo = tokenCacheDao.selectByAccountId(userAccountId); if (cachePo != null) { // 将序列化的缓存内容反序列化到当前MSAL缓存实例 cacheContext.cache().deserialize(cachePo.getCacheContent()); } } @Override public void afterCacheAccess(ITokenCacheAccessContext cacheContext) { // 仅当缓存内容发生变更时执行写库,减少无效IO if (cacheContext.hasCacheChanged()) { String userAccountId = cacheContext.account().homeAccountId(); // 序列化当前缓存的所有令牌(access_token、refresh_token等) String serializedCache = cacheContext.cache().serialize(); TokenCachePo existPo = tokenCacheDao.selectByAccountId(userAccountId); if (existPo == null) { TokenCachePo newPo = new TokenCachePo(); newPo.setUserHomeAccountId(userAccountId); newPo.setCacheContent(serializedCache); newPo.setExpireAt(System.currentTimeMillis() + 90 * 24 * 3600 * 1000L); tokenCacheDao.insert(newPo); } else { existPo.setCacheContent(serializedCache); existPo.setUpdatedAt(System.currentTimeMillis()); tokenCacheDao.updateById(existPo); } } } }
3. 绑定切面对象到MSAL客户端实例
初始化ConfidentialClientApplication(授权码流使用保密客户端)时传入自定义切面:
@Bean public ConfidentialClientApplication msalClient(DbTokenCacheAspect dbTokenCacheAspect) { return ConfidentialClientApplication .builder("你的客户端ID", ClientCredentialFactory.createFromSecret("你的客户端密钥")) .authority("https://login.microsoftonline.com/你的租户ID") // 绑定自定义缓存切面 .tokenCacheAccessAspect(dbTokenCacheAspect) .build(); }
核心注意事项
- 存储到数据库的
cache_content包含refresh_token等敏感信息,必须加密存储,禁止明文保存 - 可定时清理过期的缓存记录,避免无效数据占用存储空间
- 用户主动注销应用时,需同步删除数据库中对应用户的缓存记录
- 原有
acquireToken、acquireTokenSilently的调用逻辑无需做任何修改,应用重启后只要数据库中存在有效缓存,即可静默获取令牌,无需用户重新授权
内容的提问来源于stack exchange,提问作者Foo
相关产品推荐
相关产品推荐

