DjangoでTwitterなどのOAuth 1.0認証を行う方法

 **2022年5月現在以下の方法ではエラーが出て正しく動作しません。**

---------------------
自分自身記憶が薄れつつあり間違いが含まれてる可能性があります。ご了承ください。

（Twitterの場合は）まず以下のページを参考にCONSUMER_KEYとCONSUMER_SECRETを取得してください。
[2021年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説 \| 新宿のホームページ制作会社 ITTI（イッティ）](https://www.itti.jp/web-direction/how-to-apply-for-twitter-api/)
この時コールバックURLに`http://localhost:8000/<app_name>/twitter_callback`と入力してください（ローカルでテストする時）。`<app_name>`は自分のものに変更してください。

Django自体の解説は[こちら](https://qiita.com/kaki_k/items/511611cadac1d0c69c54)を御覧ください。

# 実装
OAuthライブラリをコマンドラインからインストールします。

```
pip install oauthlib
```

OAuth認証情報を保存するためのモデルを作成します。

```python:models.py
class User(models.Model):
    twitter_access_token = models.CharField('Twitter access token', max_length=100, null=True)
    #アクセストークンをユーザーIDにする場合
    ## id = models.CharField('user id',primary_key=True, max_length=100)
    twitter_secret_key = models.CharField('Twitter secret key', max_length=100, null=True)
```

以下のようにインポートと定数を設定します。

```python:views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from main.models import User

from requests_oauthlib import OAuth1Session

#自分のコンシューマーキー、シークレットを入力してください
TWITTER_CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXX'
TWITTER_CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXX'
```


`urls.py`でTwitter認証を行うURLを指定します。この時`twitter_callback`で登録したアプリのコールバックの設定通りになってるか確認してください。

```python:urls.py
urlpatterns = [
    #--------------
    #追加
    path('twitter_oauth', views.twitter_oauth, name='twitter_oauth'),
    path('twitter_callback', views.twitter_callback, name='twitter_callback'),
]
```

```python:views.py
#Twitter認証を行うページ（メソッド）
def twitter_oauth(request):
    REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
    AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authorize'

     oauth_client = OAuth1Session(TWITTER_CONSUMER_KEY, client_secret=TWITTER_CONSUMER_SECRET)
     try:
         resp = oauth_client.fetch_request_token(REQUEST_TOKEN_URL)

         #シークレットキーが後で必要になるので一時的にクッキーに保存
         response.set_cookie("twitter_oauth_token_secret", resp.get('oauth_token_secret'))
     except ValueError as e:
         print(e)
         return

     #Twitterの認証ページに飛ばす
     return redirect(oauth_client.authorization_url(AUTHORIZATION_URL))

# Twitterで認証された後TwitterはこのURL（メソッド）にアクセスする
def twitter_callback(request):
    ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token'

    oauth_token = request.GET["oauth_token"]
    oauth_token_secret =  request.COOKIES['twitter_oauth_token_secret']
    #シークレットキーは秘密にすべきなので削除
    response.set_cookie('twitter_oauth_token_secret', '')
    oauth_verifier = request.GET["oauth_verifier"]

    oauth_client = OAuth1Session(TWITTER_CONSUMER_KEY, client_secret=TWITTER_CONSUMER_SECRET,
                                 resource_owner_key=oauth_token,
                                 resource_owner_secret=oauth_token_secret,
                                 verifier=oauth_verifier)
    try:
        resp = oauth_client.fetch_access_token(ACCESS_TOKEN_URL)
    except ValueError as e:
        print(e)
        return

    #これでユーザーのOAuthトークン、シークレットキーを取得できる
    oauth_token = resp.get('oauth_token')
    oauth_token_secret = resp.get('oauth_token_secret')
    response = redirect('<app_name>:index')#ここはTwitter認証後アクセスしてほしいページに変えてください。

    #認証情報を保存
    user = User()
    #oauth_tokenをユーザーIDにする場合
    ##user.id = oauth_token
    user.twitter_access_token = oauth_token
    user.twitter_secret_key = oauth_token_secret
    user.save()

    return response
```

以上でユーザーのOAuth情報を取得・保存できます。
また、以上の流れはOAuth1.0で共通なので例えばTumblrならばREQUEST_TOKEN_URLなどのURLを以下のように変更しコンシューマーキーなどを自分のアプリのものに切り替えればそれだけで動くコードになります。

```python
    REQUEST_TOKEN_URL = 'https://www.tumblr.com/oauth/request_token'
    AUTHORIZATION_URL = 'https://www.tumblr.com/oauth/authorize'
    ACCESS_TOKEN_URL = 'https://www.tumblr.com/oauth/access_token'
```

OAuth情報を取得した後具体的にどう使うのかは以下の記事をご覧ください。
[Tweepyでツイートやいいねを一括取得する方法](https://qiita.com/lamrongol/items/3f14634594d388c96c03)
[PyTumblrでリブログやスキを一括取得する方法](https://qiita.com/lamrongol/items/0694ad752516777e08f2)

## Gitを利用した開発環境と本番環境の両立
ローカルの開発環境と本番環境でコールバックして欲しいURLは当然異なってくるので、以下のようにして開発環境と本番環境の定数の値を変えることができます。
まず、local_env.pyというファイルを作り、開発環境用の定数を定義します。そしてファイル名を.gitignoreに追加します。

```python:local_env.py
TWITTER_CONSUMER_KEY = 'LOCAL_CONSUMER_KEY'
TWITTER_CONSUMER_SECRET = 'LOCAL_CONSUMER_SECRET'
```

そしてviews.pyの定数宣言部分を以下のようにします。

```python:views.py
try:
    from . import local_env
    TWITTER_CONSUMER_KEY = local_env.TWITTER_CONSUMER_KEY
    TWITTER_CONSUMER_SECRET = local_env.TWITTER_CONSUMER_SECRET
except ImportError:
    TWITTER_CONSUMER_KEY = 'HONBAN_CONSUMER_KEY'
    TWITTER_CONSUMER_SECRET = 'HONBAN_CONSUMER_SECRET'

```

こうすると、開発環境ではlocal_env.pyが存在するのでローカル環境用のコンシューマーキーが代入され、本番環境では（Gitでデプロイしてる場合）local_envが存在せず、`ImportError`になるので本番環境用のコンシューマーキーが代入されます。