Flask-Login/Logout สร้างระบบ Authentication Systems —[ Ep.1 Introduction, LoginManager, login_required, user_loader]

จุดประสงค์

  • เข้าใจและสามารถใช้งาน flask-login ไลบรารี่ได้
  • เข้าใจกระบวนการทำงานในระบบยืนยันตัวตน(Authentication Systems)ของผู้ใช้งาน
  • เข้าใจการทำงานของ LoginManager
  • เข้าใจ user_loader
  • เข้าใจและสามารถใช้ login_required decorator ในการจำกัดการเข้าถึงหน้าเว็บได้
  • เข้าใจกระบวนการทำงานของฟอร์มและสามารถสร้างฟอร์มในหน้าเว็บเพื่อใช้สำหรับการล็อกอิน
  • ฯลฯ
หน้า sign-up ใน Ep.11/1 ที่ผ่านมา

Flask-Login

  • เก็บ ID ของผู้ใช้ไว้ใน Session ช่วยให้สามารถทำการ Login-Logout ได้อย่างง่ายดาย
  • ช่วยจัดการฟีเจอร์ “remember me” ได้ง่าย.
  • ช่วยป้องกันการขโมย Session ของผู้ใช้จากคุ๊กกี้.
  • นำไปประยุกต์ใช้กับ 3rd Party Libraries หรือ Extension ด้าน Authorization ต่าง ๆ ได้
  • ฯลฯ

1. ทำการติดตั้ง flask-login

pip install flask-login

2. อิมพอร์ต flask-login เข้ามาใช้งาน

from flask_login import LoginManager, login_required

3. ทดสอบจำกัดการเข้าถึงหน้าเว็บ

# app.py...
@app.route('/about')
@login_required # Newdef about(): return render_template("about.html")
...
ทดสอบคลิ๊กเข้าดูหน้า about me
ยังมีเออเร่อ

4. ทำการสร้างออปเจ็คท์สำหรับเรียกใช้งานคลาส LoginManager

# app.py
...
from flask_login import LoginManager, login_required
app = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'db = SQLAlchemy(app)login_manager = LoginManager() # Login manager for flask-login # Newlogin_manager.init_app(app) # New...
ยังไม่ได้เรียกใช้งาน user_loader method
# login_manager.pyclass LoginManager(object):    ...    def user_loader(self, callback):  # เมธอด user_loader    '''    This sets the callback for reloading a user from the session. The    function you set should take a user ID (a ``unicode``) and return a    user object, or ``None`` if the user does not exist.    :param callback: The callback for retrieving a user object.    :type callback: callable    '''    self._user_callback = callback    return callback
...

5. เรียกใช้งาน user_loader

# app.py
...
class Course(db.Model):

"""Create this course table to store course details"""
...# New
# สร้างฟังก์ชันload_user สำหรับโหลดผู้ใช้จาก ID
@login_manager.user_loaderdef load_user(user_id): return User.query.get(int(user_id))
...
ไม่สามารถเข้าดูหน้านี้ได้ เพราะว่าหน้าเว็บได้ถูกป้องกันการเข้าถึงเรียบร้อย

HTML Login Form

ตอนนี้มีเพียงข้อความ Log in ใน Navbar แต่ว่ายังไม่ได้สร้างลิ้งค์ไปยังหน้า login

6. สร้างหน้า Login Form

  • ส่งข้อมูลยิงเข้าไปที่ endpoint ก็คือฟังก์ชัน login ที่ได้กำหนด url(Route) ไว้เมื่อมีการ submit หน้าฟอร์ม โดยกำหนดเป็น POST method
<form action="{{url_for('login')}}" method="POST">
  • แท็ก input ของ username กำหนด type เป็นชนิดข้อความ ตัวอักษร (text) และตัวแอตทริบิวต์ที่ส่งเข้าไปที่ฝั่งเซิร์ฟเวอร์คือ username ซึ่งในฟังก์ชัน login ของ Flask ก็จะเขียนรอรับค่าแอตทริบิวต์ตัวนี้เพื่อประมวลผลต่อไป
<input type="text" class="form-control" name="username">
  • แท็ก input ของ password กำหนด type เป็นชนิดรหัสผ่าน สังเกตได้อย่างง่าย ๆ เวลาที่เราทำการกรอกแบบฟอร์ม ถ้าฟอร์มที่เป็นรหัสผ่าน (password) จะมีเครื่องหมาย “.(Dot) หรือไม่ก็ “*(Asterisk) ซ่อนรหัสผ่านไว้ และตัวแอตทริบิวต์ที่ส่งเข้าไปที่ฝั่งเซิร์ฟเวอร์คือ password ซึ่งในฟังก์ชัน login ของ Flask ก็จะเขียนรอรับค่าแอตทริบิวต์ตัวนี้เพื่อประมวลผลต่อไป
<input type="password" class="form-control" name="password">
<!-- login.html -->{% extends 'base.html' %}{% block title %}<title>Login</title>{% endblock title %}{% block content %}<br><div class="container" style="align-items: center;">    <div class="row">        <div class="col-lg-5"><form action="{{url_for('login')}}" method="POST">                <!-- Header Text -->                <div>                    <h5 style="text-align: center;">You have to login before reading this post</h5>                    <p>Didn't have an account ? <a href="     {{url_for('sign_up')}}">Sign Up</a></p>                 </div>
<!-- Username --> <div class="form-group"> <label>Username</label> <input type="text" class="form-control" name="username"> </div>
<!-- Password --> <div class="form-group"> <label>Password</label> <input type="password" class="form-control" name="password"> </div>
<!-- Button for submitting form --> <div style="text-align: center;"> <button type="submit" class="btn btn-primary">Login</button> </div> </form><br><br> </div> </div></div>{% endblock content %}

7. สร้างฟังก์ชัน login ใน app.py เพื่อ render HTML ไปแสดงผล

# app.py
...
# New@app.route('/login')def login():
# Do nothing, only render HTML now return render_template("login.html")....
<a class="dropdown-item" href="#">Log in</a>
<!-- base.html -->...<div class="dropdown-menu" aria-labelledby="navbarDropdown">    <a class="dropdown-item" href="{{url_for('login')}}">Log in</a>    <a class="dropdown-item" href="#">Log out</a>    <div class="dropdown-divider"></div>        <a class="dropdown-item" href="{{url_for('sign_up')}}">Sign up</a></div>...
ได้หน้าฟอร์มสำหรับการล็อกอินเรียบร้อย แต่ว่ายังไม่สมบูรณ์ ต้องเขียนฟังก์ชันในฝั่ง backend เพิ่ม
Method Not Allowed
# app.py
...
# @app.route('/login') # Default is "GET" method
@app.route('/login', methods=['GET', 'POST']) New --> add "POST"
...

สำหรับ Flask-Login Ep.1 ก็ขอจบลงเพียงเท่านี้ครับ ถ้ามีคำถามหรือข้อสงสัยหรือไม่เข้าใจตรงไหนก็คอมเมนต์ได้ที่ด้านล่างบทความกันได้เลยครับ หรือถ้าอยากติชมหรือมีอะไรเสนอแนะก็คอมเมนต์เข้ามาได้เช่นกันครับ

ท่านสามารถติดตามพวกเราได้ที่ stackpython ตามช่องทางด้านล่างนี้ได้เลยครับ

--

--

--

Full Stack Python Developers

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
stackpython

stackpython

Full Stack Python Developers

More from Medium

WazirX Clone Script — A Ready Made Script That Lets You Create a Complete Venture Like Wazirx

CS373 Spring 2022 Week 12

How to Debug Spring Boot Application using Intellij

InfluxDB 2.0 Python API — needs more examples