Register เข้าสู่ระบบ ภาษา Go
Register ออกเสียงว่า เรจิสเตอร์ หรือ รีจิสเตอร์ หมายถึง การลงทะเบียน ซึ่งเราจะพบเห็นคำว่า Register ได้ จากเว็บไซต์ (Website) ต่าง ๆ ที่จัดกิจกรรม และต้องการให้ผู้ที่สนใจลงทะเบียน เพื่อร่วมกิจกรรมดังกล่าว หรือบางเว็บไซต์ที่เปิดรับสมาชิก เพื่อรับสิทธิประโยชน์ หรือรับส่วนลดต่าง ๆ ก็มักจะมีคำว่า Register ด้วยเช่นกัน คำว่า Register นี้ไม่จำเป็นต้องใช้บนคอมพิวเตอร์ (Computer) เพียงอย่างเดียว แต่สามารถพบเจอในชีวิตจริงทั่วไป เช่น ตอนที่เราสมัครเพื่อเข้ารับการอบรม หรือตอนที่เราสมัครสมาชิกใด ๆ
ข้อกำหนดเบื้องต้น
ข้อกำหนดสำหรับบทความนี้คือ คุณควรได้ทำตามบทความ Go Admin – โครงสร้างข้อมูล (struct) มาก่อน
เข้ารหัส password ด้วย bcrypt
bcrypt เป็น password hashing function ที่สร้างขึ้นจากพื้นฐานของ Blowfish cipher โดยการทำงานของ Blowfish cipher ที่การสร้าง key ใหม่ขึ้นมาจะต้องทำการ pre-processโดยใช้เวลาเทียบเก่ากับการเข้ารหัสตัวอักษรขนาด 4KB
ติดตั้ง bcrypt ด้วยคำสั่ง
go get golang.org/x/crypto/bcrypt
go mod tidy
การลงทะเบียน Register
เปิดไฟล์ authController.go เพิ่มโค้ด password, _ := bcrypt.GenerateFromPassword([]byte(data[“password”]), 14) และ แก้ไข Password: password, เพิ่ม database.DB.Create(&user)
package controllers
import (
"go-admin/database"
"go-admin/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["password_confirm"] {
c.Status(400)
return c.JSON(fiber.Map{
"massage": "password do not match",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirsName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
ไฟล์ user.go แก้ไข Password string เป็น Password []byte
package models
type User struct {
Id int
FirsName string
LastName string
Email string `gorm:"unique"`
Password []byte
}
ไฟล์ connect.go เพิ่ม DB = database
package database
import (
"go-admin/models"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Connect() {
dsn := "root:12345678@tcp(localhost:3306)/go_admin?charset=utf8&parseTime=True"
database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
DB = database
database.AutoMigrate(&models.User{})
}
ทดสอบการทำงาน
ที่ Postman คลิก Send ที่ด้านล่างแสดงข้อมูลและ Password ที่เข้ารหัสด้วย bcrypt
ดูข้อมูลที่เพิ่มเข้าไป
ที่ MYSQL -> go_admin – > คลิกขวาที่ตาราง users -> Select Top 1000 -> Results จะแสดงข้อมูลที่เพิ่มเข้าไป
ล็อกอิน เข้าสู่ระบบ
ล็อกอิน (Log in) คือการ เข้าสู่ระบบ เช่นเดียวกับคำว่า Sign in ซึ่งรูปแบบการเขียนของคำอาจจะไม่เหมือนกัน แต่เมื่อเอามาใช้ในระบบคอมพิวเตอร์ (Computer) แล้ว จะหมายถึงการเข้าสู่ระบบเช่นเดียวกัน เรามักจะพบเห็นคำเหล่านี้บนหน้าเว็บไซต์ (Website) หรือแอพพลิเคชั่น (Application) แบบต้องสมัครสมาชิกเพื่อใช้งาน โดยเมื่อสมัครสมาชิกเสร็จเรียบร้อยแล้ว สิ่งสำคัญที่ต้องใช้เข้าสู่ระบบก็คือ Username และ Password ซึ่งบางเว็บไซต์ หรือบางแอพพลิเคชั่น อาจออกแบบให้สามารถใช้ Email, เบอร์โทรศัพท์ หรือชื่อที่เราตั้งเอง ในการเข้าสู่ระบบได้อีกด้วย
ล็อกอิน (Log in)
ไฟล์ authController.go เพิ่มโค้ดดังนี้
package controllers
import (
"go-admin/database"
"go-admin/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["password_confirm"] {
c.Status(400)
return c.JSON(fiber.Map{
"massage": "password do not match",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirsName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
func Login(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
database.DB.Where("email = ?", data["email"]).First(&user)
if user.Id == 0 {
c.Status(404)
return c.JSON(fiber.Map{
"massage": "not found",
})
}
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(400)
return c.JSON((fiber.Map{
"massage": "incorrect password",
}))
}
return c.JSON(user)
}
ไฟล์ routes.go เพิ่มเส้นทางใหม่ ด้วยโค้ด app.Post(“/api/login”, controllers.Login)
package routes
import (
"go-admin/controllers"
"github.com/gofiber/fiber/v2"
)
func Setup(app *fiber.App) {
app.Post("/api/register", controllers.Register)
app.Post("/api/login", controllers.Login)
}
ทดสอบการทำงาน
ที่ Postman เปิดแท็บใหม่ ใส่ http://localhost:8000/api/login
เลือกเป็น POST -> Body -> Raw -> JSON แล้วเขียนโค้ดด้านล่าง คลิก Send
{
"email": "joth2022@doe.com",
"password": "1"
}
ด้านล่างจะแสดงข้อความ “massage”: “not found” เพราะไม่มี email นี้ในระบบของเรา
ทดสอบ อีเมล มีในระบบ แต่ password ผิด -> Send
{
"email": "joth@doe.com",
"password": "12"
}
ด้านล่างจะแสดงข้อความ “massage”: “incorrect password” เพราะ password ไม่ถูกต้อง
ทดสอบ อีเมล มีในระบบ และ password ที่ถูกต้อง -> Send
{
"email": "joth@doe.com",
"password": "1"
}
ด้านล่างจะแสดงข้อมูลในระบบ
JWT
JWT ย่อมาจาก JSON Web Token เป็นรูปแบบหนึ่งที่ใช้ในการสร้างรหัส token จากข้อมูล JSON Data แล้วทำการเข้ารหัสด้วย Base64Url Encoded
Token
เป็นรหัสชุดนึงที่เอาไว้สำหรับทดแทน session ซึ่งเอาไว้ระบุว่าคนๆนั้นคือใคร ตัวอย่างเช่น Facebook เมื่อล็อคอินเสร็จแล้วจะมี accessToken เพื่อระบุตัวตนว่าเป็นใคร ซึ่งตัว token เอามาใช้ในการทำ RESTFul API ทดแทนการทำ Web Server แบบเดิมๆ ที่เก็บในรูปแบบ session โดยตัว token จะถูกส่งไปทุกๆ request ผ่าน HTTP Headers
ติดตั้ง JWT
go get github.com/dgrijalva/jwt-go
ไฟล์ authController.go เพิ่มโค้ดดังนี้
package controllers
import (
"go-admin/database"
"go-admin/models"
"strconv"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["password_confirm"] {
c.Status(400)
return c.JSON(fiber.Map{
"massage": "password do not match",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirsName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
func Login(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
database.DB.Where("email = ?", data["email"]).First(&user)
if user.Id == 0 {
c.Status(404)
return c.JSON(fiber.Map{
"massage": "not found",
})
}
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(400)
return c.JSON((fiber.Map{
"massage": "incorrect password",
}))
}
claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
Issuer: strconv.Itoa(int(user.Id)),
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(), // 1 day
})
token , err := claims.SignedString([]byte("secret"))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
return c.JSON(token)
}
ทดสอบการทำงาน
ที่ Postman ใส่ http://localhost:8000/api/login
เลือกเป็น POST -> Body -> Raw -> JSON แล้วเขียนโค้ดด้านล่าง คลิก Send
{
"email": "joth@doe.com",
"password": "1"
}
ที่ด้านล่างจะแสดง token