概要
今回は下記の続きでログイン機能の実装を行なっていきます。
バージョン等の情報は上記の記事に記載されているので
もし知りたい方がいらっしゃれば、前回の記事を閲覧いただけると幸いです。
ログイン処理の実装
それではさっそく実装を行なっていきます。
まずは前回同様モデルの構築から行なっていきます。
モデルの構築
前回解説の際に使用したpkg/models/user.go
に追記していきます。
package models
import (
"github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
"gorm.io/gorm"
"github.com/soicchi/chatapp_backend/pkg/utils"
)
type User struct {
gorm.Model
Name string `gorm:"size:255;not null"`
Email string `gorm:"size:255;not null;unique"`
Password string `gorm:"size:255;not null"`
}
type SignUpInput struct {
Name string `json:"name" binding:"required"`
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
type LoginInput struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}
func (u *User) Create(db *gorm.DB) (User, error) {
user := User{
Name: u.Name,
Email: u.Email,
Password: utils.Encrypt(u.Password),
}
result := db.Create(&user)
return user, result.Error
}
// ここから追記
func FindUserByEmail(db *gorm.DB, email string) (User, error) {
var user User
result := db.Where("email = ?", email).First(&user)
return user, result.Error
}
func (u *User) VerifyPassword(inputPassword string) bool {
return u.Password == utils.Encrypt(inputPassword)
}
ログインする際はメールアドレスとパスワードを用いるので、
メールアドレスでユーザーを検索できるようにFindUserByEmail()
を定義しています。
また、VerifyPassword()
はログインの際のパスワードをコントローラー側で
検証するために定義しています。
さらに前回同様ログインの際にバインドさせるための構造体(LoginInput
)を定義しています。
コントローラーの定義
続いてコントローラーの定義を行なっていきます。
こちらもモデル同様に追記していきます。
func (handler *Handler) LoginHandler(context *gin.Context) {
var loginInput models.LoginInput
if err := context.ShouldBind(&loginInput); err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
"message": "Invalid request body",
})
return
}
user, err := models.FindUserByEmail(handler.DB, loginInput.Email)
if err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
"message": "Failed to find user",
})
return
}
// 入力されたパスワードとIDから取得したパスワードが等しいかを検証
if !user.VerifyPassword(loginInput.Password) {
context.JSON(http.StatusUnauthorized, gin.H{
"message": "Password is invalid",
})
return
}
context.JSON(http.StatusOK, gin.H{
"message": "Successfully logged in",
})
}
routerの設定
最後にrouter
の設定を行います。
package router
import (
"github.com/gin-gonic/gin"
"github.com/soicchi/chatapp_backend/pkg/controllers"
)
func addAuthRoutes(routerGroup *gin.RouterGroup, handler *controllers.Handler) {
auth := routerGroup.Group("/auth")
{
auth.POST("/signup", handler.SignUpHandler)
// 追記
auth.POST("/login", handler.LoginHandler)
}
}
これでログインのための一通りの実装は終わりました。
検証
では、実際に立ち上げてログインしてみましょう。
下記コマンドでコンテナを立ち上げます。
docker compose up
下記のようになれば立ち上げの成功です。
api | [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
api |
api | [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
api | - using env: export GIN_MODE=release
api | - using code: gin.SetMode(gin.ReleaseMode)
api |
api | [GIN-debug] POST /api/v1/auth/signup --> app/pkg/controllers.(*Handler).SignUpHandler-fm (3 handlers)
api | [GIN-debug] POST /api/v1/auth/login --> app/pkg/controllers.(*Handler).LoginHandler-fm (3 handlers)
api | [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
api | Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
api | [GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
api | [GIN-debug] Listening and serving HTTP on :8080
前回登録したユーザー情報は下記なので
そのユーザーIDとパスワードを使用してログインしてみます。
前回登録したユーザー情報
{"name":"sample-test", "email":"sample@sample.com", "password":"Test1234"}
下記コマンドを入力してリクエストを送ってみます。
curl -X POST -H "Content-Type: application/json" http://127.0.0.1:8080/api/v1/auth/login -d '{"email":"sample@sample.com", "password":"Test1234"}'
正常に動作していれば下記のようにレスポンスが返ってくると思います。
{"message":"Successfully logged in"}
まとめ
いかがだったでしょうか。
ログイン機能の実装自体はそれほど難しくはなかったと思います。
しかし、私が記載した方法よりももっといい方法があるかもしれません。
もしそういった意見がありましたら是非コメントしていただけると幸いです。
次回はいよいよJWT認証機能を説明します!
最後まで読んでいただきありがとうございました!