前回 書いたコード、しばらく経ってからアクセスすると AccessTokenRefreshError
なるエラーが発生することがわかった。
ERROR 2015-03-13 15:12:12,692 base.py:210] Internal Server Error: /task_manager/ Traceback (most recent call last): File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/django-1.5/django/core/handlers/base.py", line 113, in get_response response = callback(request, *callback_args, **callback_kwargs) File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/django-1.5/django/views/generic/base.py", line 68, in view return self.dispatch(request, *args, **kwargs) File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/lib/django-1.5/django/views/generic/base.py", line 86, in dispatch return handler(request, *args, **kwargs) File "/Users/yama/workspace/GAE/django_apps/utils/login.py", line 25, in check_login return handler_method(self, request, *args) File "/Users/yama/workspace/GAE/django_apps/task_manager/views.py", line 54, in get tasks = service.tasks().list(tasklist='@default').execute(http=http) File "/Users/yama/workspace/GAE/django_apps/libs/oauth2client/util.py", line 132, in positional_wrapper return wrapped(*args, **kwargs) File "/Users/yama/workspace/GAE/django_apps/libs/apiclient/http.py", line 716, in execute body=self.body, headers=self.headers) File "/Users/yama/workspace/GAE/django_apps/libs/oauth2client/util.py", line 132, in positional_wrapper return wrapped(*args, **kwargs) File "/Users/yama/workspace/GAE/django_apps/libs/oauth2client/client.py", line 494, in new_request self._refresh(request_orig) File "/Users/yama/workspace/GAE/django_apps/libs/oauth2client/client.py", line 663, in _refresh self._do_refresh_request(http_request) File "/Users/yama/workspace/GAE/django_apps/libs/oauth2client/client.py", line 710, in _do_refresh_request raise AccessTokenRefreshError(error_msg) AccessTokenRefreshError: invalid_grant
どうやら OAuth2.0 のアクセストークンの有効期限が切れていた時に当該エラーを投げている様子。
また、エラーログを見る限りエラーを raise しているのは
tasks = service.tasks().list(tasklist='@default').execute(http=http)
という行。
これを回避するには、こちらのサイト
のようにエラーを raise する可能性があるところで補足してやる方法もあるみたいだけど、
こちらの公式のサンプル
https://developers.google.com/api-client-library/python/auth/web-app#example
によると、oauth2client.client.OAuth2Credentials
クラス(これは StorageByKeyName()
から get したオブジェクト)には
そのへんの有効期限を判定するための access_token_expired
というプロパティがあるらしい。
実際のコードを見てみる。
oauth2client/client.py
@property def access_token_expired(self): """True if the credential is expired or invalid. If the token_expiry isn't set, we assume the token doesn't expire. """ if self.invalid: return True if not self.token_expiry: return False now = datetime.datetime.utcnow() if now >= self.token_expiry: logger.info('access_token is expired. Now: %s, token_expiry: %s', now, self.token_expiry) return True return False
内部で self.invalid
もやってる様子。
というわけで、既存の credentials.invalid
をこっちのプロパティで置き換えてみた。
before
if credentials is None or credentials.invalid: # --- before --- FLOW.params['state'] = xsrfutil.generate_token( settings.SECRET_KEY, user) authorize_url = FLOW.step1_get_authorize_url() logging.info(authorize_url) return HttpResponseRedirect(authorize_url) else: (Tasks API を使って処理)
after
if credentials is None or credentials.access_token_expired: # --- after --- FLOW.params['state'] = xsrfutil.generate_token( settings.SECRET_KEY, user) authorize_url = FLOW.step1_get_authorize_url() logging.info(authorize_url) return HttpResponseRedirect(authorize_url) else: (Tasks API を使って処理)
しばらくこれで様子見。
TODO
アクセストークンの有効期限ってどこかに明記されてるのかな。。。
リファレンス
OAuth2 のフローについて(日本語) http://g-master.appspot.com/article/30001/50001/50002.html