1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Flask]簡易ログイン機能+多言語JSONのDB[RESTful]

Posted at

#簡易ログイン機能+多言語JSONのDBを作るa.jpg
新年あけましておめでとうございます。この記事では、旧年の成果を発表いたしたいと思います。筆者のTwitter: yosiyos38795255 GitHub: @yosiyoshi です。よろしくお願いいたします。
##(1)必要な環境
まず、Python3の開発環境(筆者の場合はAnaconda3+Spyder)が必要。

次にpipでWebフレームワークのFlaskをインストール:
pip install Flask
あとはcurlなどがインストールされているならば、それを利用すること。

##(2)目標
RESTfulなJSONデータベースを利用して簡単なログインシステムと、その認証後に開始されるデータベースのバックエンドコードを実装すること。ただし、実はデータベース本体にログイン機能は付属しないので、ログインを通さずに操作できます(要するにログインもどき)。

##(3)実装
https://github.com/yosiyoshi/flask_practice

まず、ログイン機能の実装は以下のライブラリを使用します。

from flask import Flask, render_template, jsonify, request
import json
import re
import subprocess
import webbrowser

ユーザデータはcurlによりJSON形式で予め登録されるものとします。
まず、JSON-APIのI/Oを司るバックエンドコードをlogin.pyとして、まずその基礎部分を以下のように作成します:

app = Flask(__name__)

data = []

@app.route('/')
def form():
   return render_template('login.html')

@app.route('/data', methods=['POST'])
def add_data():
  data.append(request.get_json())
  return '', 204

#ここにログイン処理を書く

if __name__ == "__main__":
    app.run(host='localhost', debug=True)

@app.route('/')とは、
$ python login.py
実行時にアクセスできるローカルアドレス"localhost(:5000)"で行なわれる処理の定義を宣言するものです。次の行にある、def form():以降のrender_template('login.html')が、実行されるlogin.pyのディレクトリ直下に存在する"templates/login.html"を呼び出し、これをテンプレートとして読み込むのです。

@app.route('/data', methods=['POST'])とは、"localhost:5000/data"へのJSONデータの書き込みを許可するもので、コード実行中に当該アドレスへのcurl使用が可能です。

curl -i -H "Content-Type: application/json" -d "{\"id\":\"a\",\"password\": \"a\"}" http://localhost:5000/data

例えば、以上のコードを実行すると、"localhost:5000/data"に存在するデータベースへ、

{"id":"a","password": "a"}

というJSONデータが書き込まれます。ただし後述するログイン処理を考慮に入れると、ログインするのに必要なJSONデータは一つ(つまり一人分のidとpasswordの組合せ)だけです。なお、当該アドレス"localhost:5000/data"へのブラウザによるアクセスは許可されません。したがって、外部からのデータ読み込みはできません。

次に、ログイン処理を書きます:

@app.route('/auth', methods = ['POST', 'GET'])
def result():
   if request.method == 'POST':
      getkey = request.form['key']
      getvalue = request.form['value']
      authkey = "id:"+getkey+",password:"+getvalue
      jsdump = json.dumps(data)
      key = re.sub(r'["{[/ \]}"]', "", jsdump)
      if key == authkey:
         auth_res = "Login successful"
     #ログイン後にサブプロセスを起動したいので、後にここへ追記
      else:
         auth_res = "Login failed"
      return "Result: {}".format(auth_res)

このgetkeyとgetvalueで、idとpasswordのテキストフォームに入力された文字列を呼び出し、authkeyという新しい文字列に結合します。jsdumpでは、先ほど入力された
{"id":"a","password": "a"}
のようなJSONデータをstringデータに変換し、
keyで{}や[]のようなJSONデータ内に元々含まれていた記号を、re.sub(文字列,"")の命令により空文字へ置き換え、削除します。

そして、key(登録されていたJSONのidとパスワード) == authkey(入力されたidとパスワード)が一致した場合にauth_res(ログイン結果)として"Login successful"、あるいはそうでなければ"Login failed"を返します。

b.jpg
ログインフォーム

c.jpg
ログインが成功すると、この表示が出ます。

ここまでのコード: https://github.com/yosiyoshi/flask_practice/blob/master/login.py

/templatesディレクトリにlogin.htmlを作成:

<html>
   <body>
      <form action = "/auth" method = "POST">
         <p>Name /ID: <input type = "text" name = "key" /></p>
         <p>Password: <input type ="text" name = "value" /></p>
         <p><input type = "submit"  value = "submit" /></p>
      </form>
   </body>
</html>

ここまでのコード: https://github.com/yosiyoshi/flask_practice/blob/master/templates/login.html

さて、ログインが成功したのちの処理を"lang_json.py"として次のように記述:

from flask import Flask, jsonify, request
from ynltk import Langvowel
from collections import Counter
import json

app = Flask(__name__)
l = Langvowel()

data = []

@app.route('/')
def info():
  return "'/data' to show the content; '/lang' to detect in what language written; '/len' to measure the length."

@app.route('/auth')
def message():
   return "Login successful: please visit http://localhost:5000/ again."

@app.route('/data')
def get_data():
  return jsonify(data)

@app.route('/lang')
def detec_lang():
  return l.langvowel(str(data))

@app.route('/len')
def json_len():
  return str(len(json.dumps(data)))

@app.route('/data', methods=['POST'])
def add_data():
  data.append(request.get_json())
  return '', 204

if __name__ == '__main__':
    app.run(host='localhost',debug=True)
    print("Index information is here -> http://localhost:5000/")

ynltkは私がhttps://github.com/yosiyoshi/IntelligenTXT/blob/master/ynltk.py
にて公開している自然言語処理のライブラリで、今回は言語判定に利用します。

まずこのコードを実行すると、curlを通じてJSONデータのI/Oと"localhost:5000/data"のデータへアクセスすることができます。

rest2.png

そして、"/data"では登録されたデータを一覧にしてみることができます。

rest3.png

"/len"ではJSONデータの「長さ(文字数?)」が計算され、返されます。
rest4.png

"/lang"では入力されたJSONデータの言語が判別され、返されます。
rest5.png

ここまでのコード: https://github.com/yosiyoshi/flask_practice/blob/master/lang_json.py

先にlogin.py(簡易ログイン)lang_json.py(JSONデータベース)という二つのコードを独立して書きましたが、ここから先は二つの機能を連携させる必要があります。つまり、ログイン→データベース操作というフローを完成させるのです。

そのため、login.pyを小改造し、log2json.pyに書き換えます:

#@app.route('/auth', methods = ['POST', 'GET'])
#def result():
#   if request.method == 'POST':
#      getkey = request.form['key']
#      getvalue = request.form['value']
#      authkey = "id:"+getkey+",password:"+getvalue
#      jsdump = json.dumps(data)
#      key = re.sub(r'["{[/ \]}"]', "", jsdump)
#      if key == authkey:
#         auth_res = "Login successful"
         subprocess.call(['python', 'lang_json.py'])
         url = "http://localhost:5000/"
         webbrowser.open(url)
#      else:
#         auth_res = "Login failed"
#      return "Result: {}".format(auth_res)

コメントアウトされていない部分のコードを、"localhost:5000/auth"の挙動に追加することで、"Login successful"が表示される前に、先述の'lang_json.py'が起動します。

この時ログインが成功すると、

c.jpg
を表示することなく、次のような画面が表示されます:

d.jpg

こうなれば成功です。
ここまでのコード: https://github.com/yosiyoshi/flask_practice/blob/master/log2json.py

##(3)まとめ
a.jpg
まずログインすると、データベースに誘導されます。
d.jpg
データベースはRESTfulスタイルで、外部から編集できます。
result.png

##(4)最後に
駄文長文失礼しました。もともとこれらのコードは独立しており、Flaskの演習として弄っていました。従って注意が及ばず、言葉足らずや知識不足の部分も残っていると思います。ご指摘やご教授は歓迎いたします。ご閲覧ありがとうございました。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?