Python Django中Google OAuth2令牌过期后仍有效是什么原因?
问题根因
- 时区不匹配导致
credentials.expired判断失效
Google OAuth返回的credentials.expiry是UTC时区的datetime对象,你存到数据库的时候用strftime转成了不带时区信息的字符串,从数据库读取后重建credentials实例时,如果init_creds_instance函数将该字符串转成了本地时区的datetime,就会导致时间比对出现偏差:实际已经过期的UTC时间,会被判定为还未到过期时间,所以永远走不到你写的刷新分支。 - API请求未报错是Google客户端库自动刷新导致的
你手动校验过期token返回无效,但是调用Google API正常,是因为google-api-python-client库本身内置了令牌有效性校验和自动刷新逻辑:当你传入的credentials带有refresh_token时,库在发起请求前会自动判断令牌是否过期,如果过期会自动调用刷新接口获取新的access_token再发起请求,所以不会抛出错误,和你自己写的google_oauth_check_token逻辑无关。 - 数据库更新逻辑存在两处错误
你当前google_oauth_check_token函数里的更新代码:- 过滤条件写错:
SystemServiceTokens.objects.filter(id=user_id)中的id是SystemServiceTokens表的主键,不是用户外键,应该改成filter(user_id=user_id)才能命中对应用户的凭证记录 - 只更新了access_token,没有同步更新
expires_at字段,就算刷新逻辑生效,下次从数据库读取的还是旧的过期时间,判断逻辑还是会出错。
- 过滤条件写错:
修复方案
- 存储和读取
expires_at时统一使用UTC时区,不要丢失时区信息,或者直接存储令牌过期的时间戳(整数),避免时区转换错误 - 修正
google_oauth_check_token中的数据库更新逻辑,刷新令牌后同步更新token和expires_at两个字段,调整正确的过滤条件 - 如果需要自己控制刷新逻辑,可以给客户端库的build方法传入
cache_discovery=False,避免库的自动逻辑干扰你的测试。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

