2019年9月19日木曜日

WebAPI Django REST フレームワーク

【フレームワーク種】
modelsに結びつかない
1)関数ベース    @api_views
2)クラスベース  APIView

modelsに結びつく
3)Generic.view
4) ViewSets


【認証】
JWT token 解析サイト
https://jwt.io/

$ pip3 install djangorestframework djangorestframework-jwt

settings.py

REST_FRAMEWORK = {
  'DEFAULT_PERMISSION_CLASSES': (
    'rest_framework.permissions.IsAuthenticated',
  ),
  'DEFAULT_AUTHENTICATION_CLASSES': (
    'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
  ),
}

JWT_AUTH = {
    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_ALGORITHM': 'HS256',
    'JWT_ALLOW_REFRESH': True,
    'JWT_EXPIRATION_DELTA': timedelta(days=7),
    'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=28),
}

urls.py
urlpatterns = [ 
    path('token/', obtain_jwt_token),
    path('token/verify/', verify_jwt_token),
    path('token/refresh/', refresh_jwt_token),
]


$ curl -X POST http://localhost:8000/api/token/
{"email":["この項目は必須です。"],"password":["この項目は必須です。"]}
$ curl -X POST http://localhost:8000/api/token/ -d  "password=no3177&email=takahab@cxdnext.co.jp"

{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRha2FoYWJAY3hkbmV4dC5jby5qcCIsImV4cCI6MTU2OTQ3MDI2OCwiZW1haWwiOiJ0YWthaGFiQGN4ZG5leHQuY28uanAiLCJvcmlnX2lhdCI6MTU2ODg2NTQ2OH0.w_eU3AA73tMssNm0u9E3vYHml6tt76ev50vJNRBaw28"}

$ curl -X POST http://localhost:8000/api/v1/register/ -H "Authorization:JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRha2FoYWJAY3hkbmV4dC5jby5qcCIsImV4cCI6MTU2OTQ3NzUyNCwiZW1haWwiOiJ0YWthaGFiQGN4ZG5leHQuY28uanAiLCJvcmlnX2lhdCI6MTU2ODg3MjcyNH0.fNvVi3fIaayZ3_9bhhpdAxLhQCg3dATdIYO_85qiwro"


認証情報が届かないようだ。
{"detail":"認証情報が含まれていません。"}
vi /etc/httpd/conf.d/wsgi.conf
WSGIPassAuthorization on

これを追加すると認証できた。


【クライアントサンプルアプリ】
#!/usr/bin/env python36
# coding=utf-8
import json
import urllib.request

def get_token():
  auth_url = 'http://localhost:8000/api/token/'
  auth_data = {'password':'password','email':'mail@address.jp'}
  data = urllib.parse.urlencode(auth_data).encode('utf-8')

  obj = urllib.request.Request(auth_url, data=data, method='POST')
 
  return( __urlopen( obj ) )

def api_req( req, token ):
  url = 'http://localhost:8000/api/v1/register/'
  headers = { 'Content-Type' : 'application/json',
              'Authorization': 'JWT {0}'.format(token[ 'token' ])}
  json_data = json.dumps(req).encode('utf-8')

  obj = urllib.request.Request(url, data=json_data, method='POST', headers=headers)

return( __urlopen( obj ) )

def __urlopen( obj ):
  body = {}
  try:
    with urllib.request.urlopen(obj) as res:
    body = json.load(res)
  except urllib.error.HTTPError as err:
    body['ERROR'] = {}
    body['ERROR'][ 'code' ] = err.code
    body['ERROR'][ 'reason' ] = err.reason
    body['ERROR'][ 'headers'] = err.headers
  except urllib.error.URLError as err:
    body['ERROR'] = {}
    body['ERROR'][ 'reason' ] = err.reason 
  return body


def main():
  import io, sys
  sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

  req = {
        "version" : "01-01",
        "requestID": "0001",
        "name" : "inquiry",
        "sender" : "VR-200 No1",
        "category" : "registerAPI",
        "messages" : "伝票の問い合わせ",
        "descriptions": [{"customerID":"0000000000000100"}],
        "status" : "200"
  }

  token = get_token()

  if( 'token' in token):
    print( 'SEND REQUEST = ', json.dumps( req, indent=2, ensure_ascii=False) )
    body = api_req( req, token )

  if( 'ERROR' in token ):
    for key, val in token['ERROR'].items():
      print ( 'ERROR', key,':',val )
  elif( 'ERROR' in body ):
    for key, val in body['ERROR'].items():
      print ( 'ERROR' ,key,':',val )
  else:
    print( 'RESPONSE = ' , json.dumps(body, indent=2, ensure_ascii=False ))

if __name__ == "__main__":
main()

シャットダウン時の後処理 (shutdown)

# vi /etc/systemd/system/drop.service [Unit] Description= stop httpgwd DefaultDependencies=no Before=shutdown.target RefuseManualStart=true ...