昨日Pythonを導入したド素人がDjangoでjwtトークン認証を実装できるか試してみた

# 参考にさせていただいたサイト
[DjangoでJWTを使ったトークン認証を実装する](http://racchai.hatenablog.com/entry/2016/05/08/070000 "DjangoでJWTを使ったトークン認証を実装する")

# 今回作ったものはここに格納してます
[gaku3601/jwt_django](https://github.com/gaku3601/jwt_django "gaku3601/jwt_django")

# 早速やってく
djangorestframework-jwtなるものが必要らしいので入れておく。

```bash:コマンド
$ pip install djangorestframework-jwt
```

プロジェクトを作成する

```bash:コマンド
$ django-admin startproject jwtapp .
```

djangorestframework-jwtを利用するためには設定を変えないといけないっぽいので、以下を最下部に追記する。

```python
[jwtapp/settings.py]
REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),  
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),  
    'NON_FIELD_ERRORS_KEY': 'detail',
    'TEST_REQUEST_DEFAULT_FORMAT': 'json'
}
```

お次はルーティング設定

```python
[jwtapp/urls.py]
from django.contrib import admin
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token # 追記

urlpatterns = [
    path('admin/', admin.site.urls),
    path('jwt-token/', obtain_jwt_token), # 追記
]
```

これで動くみたいだけど、毎度ながら「migrateしろ！」と怒られるので、migrateして起動する。

```bash:コマンド
$ python manage.py migrate
$ python manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
February 19, 2019 - 23:26:17
Django version 2.1.7, using settings 'jwtapp.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```
🎉errorなく動いた(´・ω・｀)b🎉

superuserを作ってtokenが返却されるか確認してみる。

```bash:コマンド
$ python manage.py createsuperuser
Username (leave blank to use 'gaku'):
Email address: pro.gaku@gmail.com
Password:
Password (again):
Superuser created successfully.
```

起動してcurlコマンドを打って、tokenが返却されるか確認。

```bash:コマンド
$ python manage.py runserver
...別のターミナルで。。。
$ curl http://localhost:8000/jwt-token/ -d "username=gaku&password=**************"
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imdha3UiLCJleHAiOjE1NTA2MTk0MzQsImVtYWlsIjoicHJvLmdha3VAZ21haWwuY29tIn0.IBspHS2srFvwRPSBitosjfuIlGfrVFw1gJPXGeO_bEo"}
```
🎉tokenが帰ってきたyぉおおおお！🎉
tokenの中身見てみる
[jwt.io](https://jwt.io/ "jwt.io")
![スクリーンショット 2019-02-20 8.34.28.png](https://qiita-image-store.s3.amazonaws.com/0/47132/f8c796ca-573b-e6f1-0c65-3b8fc062878f.png)
ふむ(´・ω・｀)

ち♡な♡み♡に♪

```bash:コマンド
$ curl http://localhost:8000/jwt-token/ -d "username=gaku&password=*******wrong password*******"
{"detail":["Unable to log in with provided credentials."]}
```
間違ったpasswordを送ると怒られます。


## 認証付きのAPIを作成してみる。
発行したjwtを付与しないと利用できないAPIを書いてみる。

rest_frameworkを入れていない場合、以下コマンドで入れておく

```bash:コマンド
$ pip install djangorestframework
```

views.pyを作成し、以下のように編集

```python
[jwtapp/views.py]
from rest_framework.generics import GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework import status

class PingViewSet(GenericAPIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        return Response(data={'username': request.user.username}, status=status.HTTP_200_OK)
```

作成したviewsをルーティングで指定できるように、urls.pyを編集

```python
from django.contrib import admin
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
from . import views  #追記

urlpatterns = [
    path('admin/', admin.site.urls),
    path('jwt-token/', obtain_jwt_token),
    path('ping', views.PingViewSet.as_view()), # 追記
]
```

ok！起動して確認してみる

```bash:コマンド
$ python manage.py runserver
...別ターミナルで...
$ curl http://localhost:8000/ping  -H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imdha3UiLCJleHAiOjE1NTA2MjA2MzYsImVtYWlsIjoicHJvLmdha3VAZ21haWwuY29tIn0.xdEPAe9LvzZVuP1DBHeb8pfWOOiPTmX4K76tHNf15bg"
{"username":"gaku"}
```
🎉帰ってきたぁあ(´・ω・｀)🎉
ちな、tokenなしでアクセスすると

```bash:コマンド
$ curl http://localhost:8000/ping
{"detail":"Authentication credentials were not provided."}
```
と怒られます。

# おわり
とりあえず動いた。
だがしかし、AUTHENTICATION AND AUTHORIZATIONのuserでjwt tokenを発行する形になっているけどこういうものなのかな？
basic認証であれば瞬殺でjwt tokenを発行できることがわかったので、今後はOpenID等の認証も探っていきたいと思う(´・ω・｀)