今回やること
Unity側から入力した情報を登録 & ログインする機能を作ります。
前回同様、Flaskでローカルにアプリケーションサーバーを立てて利用します。
【前回】:【Unity(C#),Python】API通信勉強メモ②Flaskでローカルサーバー立ち上げ
なんもわからんなりの解釈が山盛りなのでマサカリ、オールオッケーです。
特にセキュリティ面に関してはエンジニアと名乗るのが恥ずかしいくらい疎いので
超巨大マサカリで一刀両断してもらってもしっかりと受け止めます。
実際に作成したもの
ID、パスワードを入力してのアカウント登録が行えて、
ログイン画面で実際にログインっぽいことが可能です。
行っていることのイメージです。
DBに情報が保存されているので、Editorを閉じてもアカウント情報は消えません。(たぶん)
Unity側
Unity側が行う処理としては入力した情報をローカルサーバーに送って、
レスポンスに応じてテキストを表示するだけです。
usingSystem.Collections;usingUnityEngine.Networking;usingUnityEngine;usingSystem.Text;usingUnityEngine.UI;publicclassRegistraionHTTPPost:MonoBehaviour{[SerializeField,Header("LogText")]Textm_logText;[SerializeField,Header("IDInputField")]InputFieldm_idInputField;[SerializeField,Header("PassInputField")]InputFieldm_passInputField;//接続するURLprivateconststringRegistrationURL="http://localhost:5000/registration";//ゲームオブジェクトUI > ButtonのInspector > On Click()から呼び出すメソッドpublicvoidRegistration(){StartCoroutine(RegistrationCoroutine(RegistrationURL));}IEnumeratorRegistrationCoroutine(stringurl){//POSTする情報WWWFormform=newWWWForm();form.AddField("user_id",m_idInputField.text,Encoding.UTF8);form.AddField("password",m_passInputField.text,Encoding.UTF8);//URLをPOSTで用意UnityWebRequestwebRequest=UnityWebRequest.Post(url,form);//UnityWebRequestにバッファをセットwebRequest.downloadHandler=newDownloadHandlerBuffer();//URLに接続して結果が戻ってくるまで待機yieldreturnwebRequest.SendWebRequest();//エラーが出ていないかチェックif(webRequest.isNetworkError){//通信失敗Debug.Log(webRequest.error);m_logText.text="通信エラー";}else{//通信成功Debug.Log("Post"+" : "+webRequest.downloadHandler.text);m_logText.text=webRequest.downloadHandler.text;}}}
ローカルサーバーに対して情報を送る処理は下記箇所が担っています。
ローカルサーバー側が受け取る情報としてform
にuser_id
、password
などをリクエスト情報として追加しています。
//POSTする情報WWWFormform=newWWWForm();form.AddField("user_id",m_idInputField.text,Encoding.UTF8);form.AddField("password",m_passInputField.text,Encoding.UTF8);
詳細に理解できてはいませんが、form
というのはリクエストの種類(POST,GETなど)に加えて、何かしらの情報を渡せるもののようです。WWWForm
はPOST専用のクラスです。
ローカルのアプリケーションサーバー(Flask)
こっちは本当に難しくて、
そもそも私は何をやればいいんだろうという状態が長く続いてしんどかったです。
まずはアカウント情報を登録する上でDB(データベース)というものを利用する必要があるとわかりました。
DBって何?
データベース(英: database, DB)とは、検索や蓄積が容易にできるよう整理された情報の集まり。 通常はコンピュータによって実現されたものを指すが、紙の住所録などをデータベースと呼ぶ場合もある。コンピュータを使用したデータベース・システムでは、データベース管理用のソフトウェアであるデータベース管理システムを使用する場合も多い。
【引用元】:ウィキペディア(Wikipedia)
データベースってのはソフトウェアのことらしいです。
そのデータはどこにあってどういう仕組みで成り立っているのか完全に理解するために深堀りすると、
帰ってこられなくなるって偉い人が言ってたので深くは考えません。
【参考リンク】:そもそもデータベースって何で出来ていて、どこの何にどう保存されるのでしょうか。。
DBにもいろいろと種類があって、今回利用するのはRDB(リレーショナルデータベース)っぽいです。
SQLAlchemy
データベースを実際に操作するにはSQLという言語を用いるのですが、それをPython内からやってくれる、というライブラリ
【引用元】:はじめての Flask #4 ~データベースをSQLAlchemyでいじってみよう~
だそうです。便利ですね~。今回はこちらを使います。
実装
いよいよFlask及びDBの実装です。
importhashlibfromflaskimport*fromsqlalchemyimportcreate_engine,Column,String,Integerfromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.ormimportsessionmaker,scoped_sessionapp=Flask(__name__)engine=create_engine('sqlite:///user.db')Base=declarative_base()# DBの設定
classUser(Base):__tablename__='users'id=Column(Integer,primary_key=True,unique=True)user_id=Column(String)password=Column(String)Base.metadata.create_all(engine)SessionMaker=sessionmaker(bind=engine)session=scoped_session(SessionMaker)# DBにIDとパスワード登録する
@app.route("/registration",methods=["POST"])defregistration():user=request.form["user_id"].strip()check_users=session.query(User).filter(User.user_id==user).all()ifcheck_users:return"そのユーザー名は使用済みです"else:user=User(user_id=request.form["user_id"],password=str(hashlib.sha256(request.form["password"].strip().encode("utf-8")).digest()))session.add(user)session.commit()returnstr(user.user_id.strip()+"様\nご登録ありがとうございます")# ログインできるID、パスワードの組合わせかどうかDBを見て照合
@app.route("/login",methods=["POST"])deflogin_check():user=request.form["user_id"].strip()check_users=session.query(User).filter(User.user_id==user).all()try:forlogin_userincheck_users:login_user_pass=login_user.passwordiflogin_user_pass==str(hashlib.sha256(request.form["password"].strip().encode("utf-8")).digest()):return"ログイン完了です"else:return"パスワードが異なります"except:return"登録情報が異なります"if__name__=="__main__":app.run(debug=True)# User.__table__.drop(engine) # テーブル削除用
テーブルの消し方
下記箇所のコメントアウトを解除して動かせば消えます。
User.__table__.drop(engine)# テーブル削除用
Pylintと仲良くする
VSCでpyhtonを書いているのですが、FlaskがPylintと仲良くしてくれませんでした。
そのため、Setting.jsonを開いて下記設定を追記しました。
"python.linting.pylintArgs": [
"--load-plugins",
"pylint_flask"
],
ハッシュ化
今回、ハッシュ化してセキュリティ対策もばっちりだぜ!ってのをやってみたかったんですが、
現状、②の箇所しかできていないので全く意味がないような気がしてます。
POSTを使うだけではセキュリティ不十分だよ~って記事がいっぱい出てくるので
やりとりする情報は全てハッシュ化しないとダメなのかな~と勝手に思ってます。
この辺り、詳しく知ってる方いたら教えてください。
Basic認証とDigest認証
セキュリティうんぬんを調べている際に知りました。
認証にも種類があるそうです。
Digest認証はセキュリティの観点でBasic認証より優れています。しかし、すべての環境に対応しているわけではありません。ページを利用するユーザーの環境がある程度分かっていて、対応しているブラウザを使っている場合には問題はありません。しかし、不特定多数のユーザーに向けたページで設定をする場合、Digest認証は向いていません。
一方Basic認証はセキュリティ面でDigest認証に劣っています。しかし、あらかじめセキュリティ対策が行われている環境下、例えばSSLやローカルネットワーク内などで利用する分には特に問題はないでしょう。ユーザーの環境にも左右されません。
このように、不特定多数のユーザーが使うページにユーザー認証を設定する場合はSSLと合わせたBasic認証、管理者など接続する環境が特定されている場合にはDigest認証、と状況によって使い分けるのが一般的です。
【引用元】:Basic認証(基本認証)とDigest認証、それぞれの役割と違いについて
今回実装したものはBasic認証と呼ばれるものに該当するのでしょうか。
よくわかりませんので、"お前が作ったのはどちらでもない"とかでいいので知りたいです。