pythonを使ってリアクティブなWebアプリを作りたい【開発編4】パスワードの暗号化

こちらの続きです。徐々にパワーアップしていきましょう。

[pythonを使ってリアクティブなWebアプリを作りたい【開発編3-2】](https://qiita.com/geeorgey/items/54b4fb22351a3e941cf6)

今回は、最初にサボったユーザー作成＆パスワード保存部分の改良になります。
ハッキングで生パスワードが漏れたとか、サービス登録後に平文のパスワードがメールで送られてきたとか。流石にだんだん聞かなくはなってきましたが、たまに耳にします。それはだめだ。
ということで、パスワードの暗号化と、それを使ったログイン機能の提供です。

## 今回変更したファイル
- [.env](https://github.com/geeorgey/vue_flask_template)
- [backend/models.py](https://github.com/geeorgey/vue_flask_template/blob/main/backend/models.py)
- [backend/flask-migrateDB.py](https://github.com/geeorgey/vue_flask_template/blob/main/backend/flask-migrateDB.py)
- [backend/auth.py](https://github.com/geeorgey/vue_flask_template/blob/main/backend/auth.py)
- [requirements.txt](https://github.com/geeorgey/vue_flask_template/blob/main/requirements.txt)

## 参考にしたQiita
[Flaskで始めるSNSチュートリアル](https://qiita.com/revvve44/items/b91e0a1fc6d5eb9a31c8)

## 何をしたのか

### .envの追記
export SECRET_KEY="Put*YOUR*SECRET*KEY"

環境変数を一つ追加してあります。
Put*YOUR*SECRET*KEY
部分はご自分のキーに変更してください。何でも良いです。ランダム文字列にしましょう。

### flask_bcryptのインストール
[requirements.txt](https://github.com/geeorgey/vue_flask_template/blob/main/requirements.txt)にかかれていますが、flask_bcryptをインストールしました。
pipenv install flask_bcrypt
してあります。


### models.pyの追記
[backend/models.py](https://github.com/geeorgey/vue_flask_template/blob/main/backend/models.py)

```python:backend/models.py
from flask_bcrypt import generate_password_hash, check_password_hash

class User(UserMixin, db.Model):
#中略
    def __init__(self, email, password):
        """ ユーザ名、メール、パスワードが入力必須 """
        self.email = email
        self.password = generate_password_hash(password).decode('utf-8')

    def check_password(self, password):
        """ パスワードをチェックしてTrue/Falseを返す """
        return check_password_hash(self.password, password)

    def reset_password(self, password):
        """ 再設定されたパスワードをDBにアップデート """
        self.password = generate_password_hash(password).decode('utf-8')

    @classmethod
    def select_by_email(cls, email):
        """ UserテーブルからemailでSELECTされたインスタンスを返す """
        return cls.query.filter_by(email=email).first()
```

こちらを追記してあります。

### flask-migrateDB.pyの微調整
[backend/flask-migrateDB.py](https://github.com/geeorgey/vue_flask_template/blob/main/backend/flask-migrateDB.py)
こちらには暗号化のキーを読み込ませる必要があります。

```Python:backend/flask-migrateDB.py
app = Flask(__name__)
# データベースファイルは実行ファイルと同じ場所にapp.dbという名前で作成
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get("SQLALCHEMY_DATABASE_URI") or "sqlite:///app.sqlite3"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") #←こちらを追記
```

### auth.pyの微調整

```Python:backend/auth.py
@auth.route("/auth/login", methods=["POST"])
def login():
    email = request.json.get("username", None)
    password = request.json.get("password", None)
    user = User.select_by_email(email)
    print('/auth/login')
    print(user)
    if user and user.check_password(password):
        """ ユーザに対してログイン処理を施す """
        return jsonify(
            access_token='test'
            ,expires_in=3600
            ,user_id=user.id
            ), 200
    elif user:
        return jsonify({"message": "メールアドレスとパスワードの組み合わせが間違っています。"}), 400
    else:
        return jsonify({"message": "存在しないユーザです"}), 400
```

ユーザの認証方法が
１：メールアドレスでまずはユーザーを取得
user = User.select_by_email(email)
2：ユーザが存在する場合はuser.check_password(password)でパスワードのマッチングをチェックする

というやり方になっています。

### 登録時にパスワードを暗号化する
/auth/register
で行っている処理は前とほぼ変えていません。それでも暗号化されているのはなぜかというとモデルに答えがあります。

```backend/models.py
    def __init__(self, email, password):
#中略
        self.password = generate_password_hash(password).decode('utf-8')
```

ここですね。この設定があることによって暗号化されるという訳です。

## 最後に登録されたテーブルを見てみましょう

![user_–_q4_–_qa4u.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/7ff78c16-9b25-9a3d-68df-cea20df4a570.png)

最初のadminは暗号化前です。
それ以下が.envのSECRET_KEYを使って暗号化されたパスワードとなっていることが分かります。



## 関連リンク
- [pythonを使ってリアクティブなWebアプリをお手軽に1分で作りたい](https://qiita.com/geeorgey/items/ace37bd92841c9d1a378)
- [pythonを使ってリアクティブなWebアプリを作りたい【基礎編】](https://qiita.com/geeorgey/items/3f86b207cd412680b835)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編】](https://qiita.com/geeorgey/items/ea60afe0c44a5f9db483)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編2】](https://qiita.com/geeorgey/items/961c1d1092ec60bb06bd)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編3】](https://qiita.com/geeorgey/items/1f5544b12e7d26a1216c)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編3-2】](https://qiita.com/geeorgey/items/54b4fb22351a3e941cf6)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編4】パスワードの暗号化](https://qiita.com/geeorgey/items/85905a4772903b180fad)
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Herokuの開発環境と本番環境](https://qiita.com/geeorgey/items/b080617f5332ab7255c4)←イマココ
- [pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Slack boltの組み込み](https://qiita.com/geeorgey/items/ca2942ff054e30587c78)