[Unity (C #), Python] API communication study memo ③ Implementation of simplified login function

What to do this time

Create a function to register & log in the information entered from the Unity side. As before, we will set up and use an application server locally in Flask.

[Last time]: [Unity (C #), Python] API communication study memo ② Launch local server with Flask

Masakari is all okay because there are a lot of interpretations that I don't understand. ** Especially when it comes to security, it's embarrassing to call myself an engineer ** Even if you cut it with a huge Masakari, it will be accepted firmly.

What was actually created

GetHIKAKIN.gif

You can register an account by entering your ID and password. You can actually log in on the login screen.

It is an image of what you are doing.

ログインイメージ.PNG

Since the information is saved in the DB, the account information will not be deleted even if you close the Editor. (maybe)

Unity side

The process performed by Unity is to send the entered information to the local server and Just display the text in response.

Processing related to registration button


using System.Collections;
using UnityEngine.Networking;
using UnityEngine;
using System.Text;
using UnityEngine.UI;

public class RegistraionHTTPPost : MonoBehaviour {

    [SerializeField, Header("LogText")]
    Text m_logText;

    [SerializeField, Header("IDInputField")]
    InputField m_idInputField;

    [SerializeField, Header("PassInputField")]
    InputField m_passInputField;

    //URL to connect to
    private const string RegistrationURL = "http://localhost:5000/registration";

    //Game object UI>Button Inspector> On Click()Method to call from
    public void Registration()
    {
        StartCoroutine(RegistrationCoroutine(RegistrationURL));
    }

    IEnumerator RegistrationCoroutine(string url)
    {
        //Information to POST
        WWWForm form = new WWWForm();
        form.AddField("user_id", m_idInputField.text, Encoding.UTF8);
        form.AddField("password", m_passInputField.text, Encoding.UTF8);

        //Prepare URL by POST
        UnityWebRequest webRequest = UnityWebRequest.Post(url, form);
        //Set buffer in UnityWebRequest
        webRequest.downloadHandler = new DownloadHandlerBuffer();
        //Connect to the URL and wait for the results to come back
        yield return webRequest.SendWebRequest();

        //Check for errors
        if (webRequest.isNetworkError)
        {
            //Communication failure
            Debug.Log(webRequest.error);
            m_logText.text = "Communication error";
        }
        else
        {
            //Successful communication
            Debug.Log("Post"+" : "+webRequest.downloadHandler.text);
            m_logText.text = webRequest.downloadHandler.text;
        }
    }
}

The following parts are responsible for sending information to the local server. As information received by the local server side ʻUser_id, password, etc. are added to form` as request information.

Information to send at the time of request


    //Information to POST
    WWWForm form = new WWWForm();
    form.AddField("user_id", m_idInputField.text, Encoding.UTF8);
    form.AddField("password", m_passInputField.text, Encoding.UTF8);

I don't understand in detail, but form seems to be able to pass some information in addition to the request type (POST, GET, etc.). WWWForm is a POST-only class.

Local application server (Flask)

This is really difficult, ** What should I do in the first place ** It was a long and difficult situation.

First of all, I found out that it is necessary to use a DB (database) to register account information **.

What is DB?

A database (English: database, DB) is a collection of information organized for easy retrieval and storage. Usually, it refers to what is realized by a computer, but a paper address book may be called a database. In a database system using a computer, a database management system, which is software for managing the database, is often used.

[Source]: [Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3 % 83% BC% E3% 82% B9)

The database seems to be software. If you dig deeper to fully understand where the data is and how it works, I don't think deeply because a great person said that I wouldn't be able to come back. [Reference link]: What is a database made of in the first place, and where and how is it stored? ..

There are various types of DB, and this time I use it like ** RDB (relational database) **.

SQLAlchemy

A library called SQL is used to actually operate the database, but it is done from within Python.

[Source]: First Flask # 4 ~ Let's play with the database with SQLAlchemy ~

That's right. It's convenient! This time I will use this.

Implementation

It's finally Flask and DB implementation.

import hashlib

from flask import *

from sqlalchemy import create_engine, Column, String, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, scoped_session

app = Flask(__name__)

engine = create_engine('sqlite:///user.db')
Base = declarative_base()


#DB settings
class User(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)


#Register ID and password in DB
@app.route("/registration", methods=["POST"])
def registration():

    user = request.form["user_id"].strip()
    check_users = session.query(User).filter(User.user_id == user).all()

    if check_users:
        return "That username has been used"
    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()
        return str(user.user_id.strip() + "Mr\n Thank you for registering")

#Check the DB to see if it is a combination of ID and password that can be logged in
@app.route("/login", methods=["POST"])
def login_check():

    user = request.form["user_id"].strip()
    check_users = session.query(User).filter(User.user_id == user).all()

    try:
        for login_user in check_users:
            login_user_pass = login_user.password

        if login_user_pass == str(hashlib.sha256(
                request.form["password"].strip().encode("utf-8")).digest()):
            return "Login is complete"
        else:
            return "Password is different"
    except:
        return "Registration information is different"


if __name__ == "__main__":
    app.run(debug=True)
    # User.__table__.drop(engine)  #For table deletion

How to erase the table

If you uncomment the following part and move it, it will disappear.

  User.__table__.drop(engine)  #For table deletion

Make friends with Pylint

I'm writing pyhton in VSC, but Flask didn't get along with Pylint.

Therefore, I opened Setting.json and added the following settings.

"python.linting.pylintArgs": [
        "--load-plugins",
        "pylint_flask"
    ],

Hashing

This time, I wanted to do ** hashing and security measures are perfect! ** At present, only part (2) has been created, so I feel that it is completely meaningless. There are a lot of articles saying that security is not enough just by using POST. I'm wondering if all the information to be exchanged must be hashed. If you know more about this area, please let me know.

ログインイメージ.PNG

Basic and Digest authentication

I found out when I was investigating security. It seems that there are different types of authentication.

Digest authentication is superior to Basic authentication in terms of security. However, it is not compatible with all environments. If you know the environment of the user who uses the page to some extent and you are using a compatible browser, there is no problem. However, Digest authentication is not suitable for setting on a page for an unspecified number of users.

On the other hand, Basic authentication is inferior to Digest authentication in terms of security. However, there should be no problem if you use it in an environment where security measures are taken in advance, such as SSL or in a local network. It does not depend on the user's environment.

In this way, when setting user authentication on a page used by an unspecified number of users, Basic authentication combined with SSL, Digest authentication when the connection environment such as an administrator is specified, depending on the situation Is common.

[Source]: Basic authentication (basic authentication) and Digest authentication, their roles and differences

Does the one implemented this time correspond to what is called Basic authentication? I'm not sure, so I'd like to know because it's okay to say, "You didn't make either."

Reference link

[Python ORM] Summary of basic SQL queries with SQLAlchemy

Recommended Posts

[Unity (C #), Python] API communication study memo ③ Implementation of simplified login function
Implementation of login function in Django
Crawling with Python and Twitter API 2-Implementation of user search function
Python & Machine Learning Study Memo ⑤: Classification of irises
Python & Machine Learning Study Memo ②: Introduction of Library
Memo of "Cython-Speeding up Python by fusing with C"
C API in Python 3
TensorFlow API memo (Python)
A memo of writing a basic function in Python using recursion
[python] Value of function object (?)
[Line / Python] Beacon implementation memo
[Python] Etymology of python function names
Python implementation of particle filters
Implementation of quicksort in Python
Implementation of CRUD using REST API with Python + Django Rest framework + igGrid
Geometry> Clockwise angle calculation of two vectors> Link: python implementation / C implementation