0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

pyotp を使ったワンタイムパスワードの実装

Last updated at Posted at 2025-04-09

pythonのライブラリである pyotp を使うと簡単にワンタイムパスワードが実装できます。

  1. まずは環境を構築します

    $ apt-get update
    $ apt-get install -y curl wget vim
    $ python3 python3.12-venv
    $ python3 -m venv /work/python
    $ /work/python/bin/pip install flask
    $ /work/python/bin/pip  install pyotp 
    $ /work/python/bin/pip  install qrcode
    $ /work/python/bin/pip install pillow
    $ /work/python/bin/pip install BytesIO
    
  2. アプリを作成します。本来はキー情報はDBに格納が必要ですが、今回はJSONファイルに書き出しています。

    from flask import Flask, render_template, request
    import pyotp
    import qrcode
    import os
    import json
    import base64
    from io import BytesIO
    
    app = Flask(__name__)
    
    # 初期画面
    @app.route('/index')
    def index():
        return render_template('index.html')
    
    # 登録画面
    @app.route('/regist', methods=['POST'])
    def regist():
        userid = request.form['userid']
        key = pyotp.random_base32()    
    
        with open('/work/data/test.json') as f:
            d = json.load(f)
    
            d[userid] = key
            data_str = json.dumps(d)
        with open('/work/data/test.json', mode='w') as f:
            f.write(data_str)
    
        totp = pyotp.TOTP(key)
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=5,
            border=2,
        )
        qr.add_data(totp.provisioning_uri(name=userid, issuer_name="KstoneriverSampleApp"))
        qr.make(fit=True)
        img = qr.make_image(fill_color="black", back_color="white")
        buffered = BytesIO()
        img.save(buffered, format="JPEG")
        img_str = base64.b64encode(buffered.getvalue()).decode("ascii")
        return render_template('regist.html', img=img_str, userid=userid)
    
    # 登録結果
    @app.route('/validate', methods=['POST'])
    def validate():
        userid = request.form['userid']
        otp = request.form['otp']
    
        with open('/work/data/test.json') as f:
            d = json.load(f)
            key = d[userid]
    
        totp = pyotp.TOTP(key)
        result = totp.verify(otp)
        if result:
            ret_str = "Success!!"
        else:
            ret_str = "Failed..."
    
        return render_template('result.html', ret = ret_str)
    
    if __name__ == '__main__':
        app.run(host="0.0.0.0", port=5000, debug=True)
    
    
  3. 実行します

    /work/python/bin/python app.py
    
    • ユーザIDの登録画面が表示されます
      index.png
    • ユーザIDを入力して送信ボタンをクリック
      index_input.png
    • QRコードが表示されます。
      regist.png
    • QRコードをGoogle Authenticatorなどで読み取り登録し、6桁の数字を入力します。
      regist_input.png
    • 送信ボタンをクリックして、「Success!」と表示されれば成功
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?