You are hereBlogs > jittat's blog > หน้าเฉพาะผู้ใช้ที่ลงทะเบียนแล้ว

หน้าเฉพาะผู้ใช้ที่ลงทะเบียนแล้ว


By jittat - Posted on 02 October 2008

Django มาพร้อมกับ app มาตรฐาน django.contrib.auth ที่จัดการเกี่ยวกับผู้ใช้ (การ login การจัดการเกี่ยวกับเข้าถึงหน้าต่าง ๆ) ที่ใช้งานได้ไม่ยาก โดยปกติแล้วตัว app นี้จะถูกติดตั้งมากับโครงงานของเราโดยอัตโนมัติเมื่อเริ่มสร้าง

ในตอนนี้ เราจะใช้ django.contrib.auth เพื่อสร้างการจัดการผู้ใช้อย่างง่าย สำหรับโปรแกรมประยุกต์ที่มีหน้าพิเศษที่ต้องการให้เฉพาะ user ที่มีในระบบเท่านั้นเข้าได้

เกี่ยวกับเรื่องนี้เรามีเอกสารอ้างอิงหลักคือ: User authentication in Django

สมมติว่าเรามีโครงงานเก่าอยู่แล้วนะครับ โครงงานนี้จะต้องมี app django.contrib.auth ติดตั้งอยู่ก่อนแล้ว และมีการกำหนด user แล้ว ส่วนการเริ่มสร้างโครงงาน รวมถึงการปรับแต่งทั่วไปดูได้จากเอกสารอื่น ๆ ใน django66 นี้ครับ

เกี่ยวกับ user ของโครงงาน โดยมากทุก ๆ โครงงานใน Django ก็จะมี superuser แล้ว (ถูกสร้างเมื่อสั่ง manage.py syncdb ครั้งแรก) หลังจากนั้นก็สามารถเพิ่ม user ได้ผ่านทางระบบ admin ของ Django ดังนั้นในตอนนี้เราจะยังไม่สนใจเรื่องการลงทะเบียน user นะครับ

ภาพรวมของขั้นตอนที่เราจะทำเป็นดังด้านล่าง

  • สำหรับ view ที่ต้องการรับประกันว่า user ที่มีในระบบเท่านั้นจะเข้าได้ ให้ระบุ decorator @login_required เอาไว้
  • ถ้าผู้ใช้ที่ไม่ได้ login เรียกไปยัง view ดังกล่าว จะถูก redirect ไปหน้า login ซึ่งระบุด้วยค่าพารามิเตอร์ LOGIN_URL ใน settings.py
  • ในการจัดการแสดงหน้า login (ที่เราต้องสร้าง template เตรียมไว้) และการประมวลผลการ login เราจะใช้ django.contrib.auth.views.login ที่มากับ Django ซึ่งถ้าผู้ใช้ login ได้เรียบร้อยจะ redirect ผู้ใช้ไปยังหน้าที่ต้องการ (หรือถ้าไม่ระบุจะไปที่หน้า LOGIN_REDIRECT_URL)
  • ถ้าต้องการ logout เราก็จะเรียกใช้ view django.contrib.auth.views.logout

มาทำไปทีละขั้นกันครับ

อย่างแรกที่ระบบจัดการผู้ใช้ต้องมีก็คือการปิดกั้นการเข้าถึงบางหน้า เราจะใช้วิธีลัดสั้นด้วย decorator @login_required สมมติว่าเรามีวิว list ที่ต้องการจำกัดการเข้าถึงให้ได้เฉพาะผู้ใช้ที่ได้ login เอาไว้แล้วเท่านั้น เราก็แปะ decorator ดังกล่าวหน้าฟังก์ชันตามด้านล่าง

# ต้อง import ก่อนถึงจะมี login_required ใช้
from django.contrib.auth.decorators import login_required

@login_required
def list(request):
    return render_to_response("list.html",{})

ถ้าทดลองใช้เลย จะพบว่าเมื่อเรียกไปที่ url ที่โยงมาที่ฟังก์ชันนี้ จะมี error ปรากฏขึ้น ระบุว่า ไม่มีหน้าที่รองรับ /accounts/login/

login_required จะตรวจสอบว่าผู้ใช้ปัจจุบัน login แล้วหรือยัง ถ้ายังไม่ได้ login ก็จะ redirect มายังหน้าสำหรับ login ซึ่งถ้าเราไม่ได้ระบุอะไรไว้ ก็จะเป็น url ดังกล่าว

เราสามารถตั้งค่า url ที่จะ redirect ไปเพื่อ login ได้ที่ตัวแปร LOGIN_URL ใน settings.py เช่น อาจตั้งให้ไปที่ /login/

LOGIN_URL = "/login/"

จากนั้นก็ไปแก้ url mapping ใน urls.py ให้ไปเรียกใช้ฟังก์ชัน login ที่มากับ django.contrib.auth โดยไปเพิ่มบรรทัดด้านล่าง

    (r'^login/$','django.contrib.auth.views.login'),

ในการใช้งานฟังก์ชัน login ดังกล่าว เราจะต้องสร้าง template สำหรับหน้า login เอาไว้ ถ้าไม่ระบุเพิ่มในการเรียกใช้ ตัว view ดังกล่าวจะแสดง template ชื่อ registration/login.html เราสามารถระบุ template ได้โดยระบุพารามิเตอร์ template_name ในการเรียก view ดังกล่าว เช่น

    (r'^login/$','django.contrib.auth.views.login',
     {'template_name' : 'login.html'}),

ในการ render template ดังกล่าว จะมีการส่งพารามิเตอร์ form, next และ site_name ให้ template นั้นแสดง โดยพารามิเตอร์ที่เราจะทดลองใช้คือ form แทนฟอร์มสำหรับป้อนชื่อผู้ใช้และรหัสผ่าน, และ next จะระบุเป็น url ที่ทำให้เรียกมาหน้า login นี้ โดยเรามักจะใช้เพื่อระบุ url ที่จะ redirect ไปถ้าผู้ใช้ login ได้ถูกต้อง

เราเขียน template ง่าย ๆ ได้ดังด้านล่างครับ

<h1>Login</h1>
<form action="/login/" method="post">
  {{ form.as_p }}
  <input type="hidden" name="next" value="{{ next }}"/>
  <input type="submit" value="Login"/>
</form>

สังเกตว่า ใน form เราจะเรียกไปยัง url ของ views.login เดิม แต่ต้องส่ง request ด้วยการ post เนื่องจาก views.login จะตรวจสอบการเรียกใช้ว่าเป็นการ login หรือเป็นการเรียกให้แสดงหน้า login เฉย ๆ จากวิธีการเรียกมายัง url นั้น

ใน form ดังกล่าว เราก็แสดงตัวแปร form และส่งค่า next (แบบซ่อน) มาด้วย

ถ้าผู้ใช้ login ได้เรียบร้อย views.login จะ redirect ผู้ใช้ตามที่เราระบุในค่า next ถ้าเราไม่ได้ระบุ views.login จะ redirect ไปตามค่าพารามิเตอร์ LOGIN_REDIRECT_URL ที่ระบุใน settings.py ซึ่งค่าโดยปริยายคือ /accounts/profile/

ถ้าผู้ใช้สามารถ login ได้ เขาก็จะอยู่ในระบบไปเรื่อย ๆ จนกว่าจะ logout โดย app auth ของ Django จะจัดการเรื่อง session ต่าง ๆ ให้โดยอัตโนมัติ

ถ้าต้องการให้ผู้ใช้ logout ได้ ก็เพิ่มลิงก์สำหรับ logout ใน template จากนั้นแก้ urls.py ให้เรียกมาที่ views.logout โดยเพิ่มบรรทัดเช่นด้านล่างใน urls.py

    (r'^logout/$','django.contrib.auth.views.logout',
     {'template_name' : 'index.html'}),

หลังจากผู้ใช้ logout แล้ว view จะ render หน้าที่ระบุในพารามิเตอร์ template_name ครับ