สวัสดีครับ พบกันกับบทความที่สาวก Django หลายคนน่าจะรอคอยกันอีกหนึ่งบทความนะครับ นั่นก็คือการพัฒนาระบบ Authentication System ซึ่งจะครอบคลุมในส่วนของ การทำ login, logout ให้กับ Django โปรเจคท์ของเราครับ
Authentication System เป็นการตรวจสอบผู้ที่จะเข้าใช้งานระบบหรือกำหนด permissions ไม่ว่าจะเป็นการเข้าถึงแอปพลิเคชัน, การเข้าถึง network, devices อะไรต่าง ๆ โดยทั่วไปจะทำการตรวจสอบจาก credencials ของผู้ใช้ ซึ่งในบริบทนี้คือ username และ password ซึ่งหลาย ๆ คนก็น่าจะคุ้นเคยกันเป็นอย่างดีกับ 2 คำนี้ และในชีวิตประจำวันเราก็คุ้นเคยกันดีกับ authentication system ผ่านแอปพลิเคชันที่เราใช้ในชีวิตประจำวัน เช่น Facebook, YouTube และเว็บไซต์อื่น ๆ ที่ต้องมีการกำหนดสิทธิในการเข้าใช้งานของผู้ใช้
ซึ่ง Django นั้นก็มี authentication framework ที่มีมาให้เพียบพร้อม ให้เราได้ใช้งานได้ทันที ซึ่งสะดวกและรวดเร็วแถมเขียนโค้ดเพียงแค่ไม่กี่บรรทัด
User objects เรียกได้ว่าเป็นหัวใจหลักของระบบ Authentication System ของ Django เลยก็ว่าได้
ซึ่ง attributes ซึ่งเป็นตัว default ของ user มีดังต่อไปนี้
มีมาให้พร้อมกับ Django เรียบร้อย เมื่อเปิดเข้าดูใน settings.py จะพบกับ INSTALLED_APPS[...] ที่มี auth และ contenttypes และใน MIDDLEWARE[...] ก็จะมีทั้ง SessionMiddleware และ AuthenticationMiddleware
settings.py
INSTALLED_APPS = [ ... 'django.contrib.auth', 'django.contrib.contenttypes', ... ] MIDDLEWARE = [ ... 'django.contrib.sessions.middleware.SessionMiddleware', ... 'django.contrib.auth.middleware.AuthenticationMiddleware', ... ]
เมื่อสร้างโปรเจคท์ขึ้นมาเรียบร้อยแล้ว สามารถทำการ migrate ได้ทันที ซึ่งตารางที่เก็บข้อมูลของ user จะมีชื่อว่า "auth_user" ซึ่งก็จะเก็บข้อมูลซึ่งจะมีฟีลด์ต่าง ๆ ดังต่อไปนี้
ซึ่งฟีลด์ทั้งหมดที่กล่าวมาด้านบน มี 2 ฟีลด์ที่เป็น required fields คือ username และ password คือจะปล่อยเป็นค่าว่างไม่ได้ ต้องใส่ข้อมูลเข้าไป ดังจะเห็นได้ในตอนสร้าง superuser ซึ่งจำเป็นต้องกรอก 2 ฟีลด์นี้ แต่ตัวอื่น ๆ เช่น email, etc ปล่อยเป็น blank (ว่าง) ได้
เมื่อทำการ migrate ตารางต่าง ๆ รวมไปถึง auth_user ด้านบนก็จะถูกสร้างและเก็บใน database
$ python manage.py migrate
ปกติแล้วหลาย ๆ คนคงคุ้นเคยกับการสร้าง username และ password ผ่านคำสั่ง
$ python manage.py createsuperuser
ซึ่งจริง ๆ แล้วนอกจากสร้างผ่าน createsuperuser เรายังสามารถสร้าง user เพื่อเข้าใช้งาน สามารถทำได้ด้วยวิธีที่ง่ายและตรงไปตรงมาที่สุดด้วยการเรียกใช้งาน helper function ที่มีชื่อว่า create_user()
โดยต้องทำการเข้าใช้งานหน้า Django Shell ก่อน
$ python manage.py shell
terminal/shell
>>> from django.contrib.auth.models import User >>> user = User.objects.create_user('Sonny', 'sonnypassword') # Save this user to a database >>> user.save()
หลังจากที่ได้ทำการทดสอบสร้าง user เสร็จแล้ว จากนั้นก็ทำการดึงข้อมูลมาแสดงผลเพื่อดูว่ามีกี่ users ใน database
terminal/shell
>>> from django.contrib.auth.models import User # Get all users from the database >>> user = User.objects.all() >>> user <QuerySet [<User: Sonny>]>
จะเห็นว่ามีเพียงแค่ user ที่มีชื่อว่า Sonny ที่เพิ่งสร้างไปเมื่อสักครู่
ทดสอบแสดงผล password ที่ได้สร้างก่อนหน้า จะเห็นว่า Django นั้นได้ทำการ hash password ไว้เป็น default ของ Django อยู่แล้ว ดังนั้นจึงไม่ต้องเขียนเพื่อทำ hash เอง และแน่นอนว่า password ที่แสดงก็จะไม่แสดงแบบ raw text หรือ plaintext แต่จะแสดงเป็น password ที่ถูกเข้ารหัสนั่นเอง ทำให้เป็นไปได้ยากที่คนอื่นจะรู้รหัสผ่านของเรา
>>> from django.contrib.auth.models import User >>> u = User.objects.get(id=1) >>> u.username 'sonny' >>> u.password # hash password 'pbkdf2_sha256$216000$eDtCSPqq7alM$oqF2Gepvqba23c23GwtcTwrmUhhW+gEXKmwNdVg3lLs='
ทำการ authenticate user ได้โดยฟังก์ชัน authenticate() ซึ่งในฟังก์ชันนี้จะทำการรับค่าเป็น keyword arguments 2 ตัวคือ username และ password ดังต่อไปนี้
terminal/shell
from django.contrib.auth import authenticate user = authenticate(username='Sonny', password='secret-password') if user is not None: # A backend authenticated the credentials # do_something else: # No backend authenticated the credentials # do_something
views.py
from django.db import models @login_required(login_url='/login-form') def protected_page(request): return render(request, 'blog/protected-page.html')
จากโค้ดด้านบนในส่วนของ decorator คือ @login_required() จะมีการส่งอากิวเมนต์ที่มีชื่อว่า login_url ซึ่งในอากิวเมนต์นี้สามารถส่ง url เข้าไปได้เลย โดยถ้า user กดเข้าดูหน้านี้ก็จะไม่สามารถเข้าดูได้ถ้ายังไม่ได้ทำการ authenticate และจะถูกลิ้งค์ไปที่หน้า /login-form ที่ถูกสร้างในฟังก์ชัน login_form() ให้โดยอัตโนมัติ โดยในฟังก์ชันนี้ก็ทำการ render หน้า login เพื่อให้ user สามารถล็อกอินเข้าใช้ได้นั่นเอง
การ login จะมีโปรเซสดังต่อไปนี้
ทำการสร้างฟังก์ชัน login_user() เพื่อที่จะกำหนดเงื่อนไขต่าง ๆ ในการล็อกอินเข้าใช้งานและทำการตรวจสอบข้อมูลที่ user ได้ทำการกรอกเข้ามาในหน้า login form
views.py
def login_user(request): # Create the variables to hold incoming inputs username = request.POST.get('username') password = request.POST.get('password') # map variables to be one instance # then authenticate a user # authenticate requires 3 arguments --> request, username, and password user = authenticate(request, username=username, password=password) if user is not None: # Log a user in login(request, user) return HttpResponse("Successful login") else: return HttpResponse("Incorrect user<br><a href=""/"">Get back to home page</a>")
home.html
<!DOCTYPE html> <html> <head> <title>Home</title> <body> <div class="container" style="text-align: center;"> <h1>This is homepage</h1> <a href="/">Home</a><br> <a href="/protected-page">Only authenticated user page</a><br> {% if user.is_authenticated %} <a href="/logout">Log out</a> {% endif %} </div> </body> </head> </html>
ยังไม่ได้ทำการล็อกอิน
ทดสอบสร้างหน้าเว็บที่ user ต้อง log in ก่อนถึงจะเข้าดูหน้าเว็บนี้ได้ โดยตั้้งชื่อว่า authenticated-user-page.html
authenticated-user-page.html
<!DOCTYPE html> <html> <head> <title>Login Form</title> <body> <p>Welcome an authenticated user, congrats !! you've a permission to access this page</p> </body> </head> </html>
ทำการสร้างหน้า UI (From) ที่มีชื่อว่า login.html เพื่อให้ user สามารถล็อกอินเข้ามาใช้งานได้
login.html
<!DOCTYPE html> <html> <head> <title>Login Form</title> <body> <h1>Login here</h1> <form method="POST" action="/login"> {% csrf_token %} <label>Username</label> <input type="text" id="username" name="username" placeholder="Username"><br> <label>Password</label> <input type="password" id="password" name="password" placeholder="Password"><br> <button type="submit">Login</button> </form> </body> </head> </html>
เมื่อทำการคลิกที่ลิ้งค์ "Only authenticated user page" จะถูก redirect มาที่หน้า login ทันที
การ logout ก็สามารถทำได้สะดวกและง่ายมาก ๆ ด้วยฟังก์ชันที่สำเร็จรูปมาให้แล้วอย่าง logout logout() ที่ Django ทำมาให้สำเร็จเรียบร้อย ซึ่งในฟังก์ชันนี้ต้องการ 1 argument นั่นก็คือ request จากนั้นก็ทำการส่งอากิวเมนต์นี้เข้าไปให้เรียบร้อยร้อย จะได้ logout(request)
จากนั้นทำการรีเทิร์นข้อความที่มีชื่อว่า You've logged our. Get back to log in "ok"
views.py
def log_user_out(request): # Log user out logout(request) return HttpResponse("You've logged out<br><a href=""/"">Get back to login</a>")
log out สำเร็จ
urls.py
from django.urls import path from .views import home, protected_page, log_user_in, login_form, log_user_out urlpatterns = [ path('', home), path('protected-page', protected_page), path('login-form', login_form), path('login', log_user_in), path('logout', log_user_out) ]
จบลงไปแล้วกับบทความ Django login, log out หวังว่าหลังจากอ่านจนจบ ทุกคนจะเข้าใจโปรเซสและภาพรวมของระบบ authentication system ด้วย django framework กันนะครับ
บทความแนะนำ
References
[ djangoproject.com ] - Using the Djagno authentication system
[developer.mozilla.org ] - User Authentication and Permissions
กิจกรรมที่กำลังจะมาถึง
ไม่พลาดกิจกรรมเด็ด ๆ ที่น่าสนใจ
Event นี้จะเริ่มขึ้นใน July 5, 2022
รายละเอียดเพิ่มเติม/สมัครเข้าร่วมโปรคอร์สรวมแรกของปี เรียนไพธอนครบครัน หลากหลาย ลดราคาจาก 7,900฿ เหลือ 6,900฿ พร้อมโบนัส รายละเอีดยเพิ่มเติมในลิงก์ ปล. สมาชิกที่เจอลิงก์นี้จากบทความของเรา แคปภาพมา แอดมินลดให้เพิ่มอีก 200 ครับ