Skip to content

Commit

Permalink
Merge pull request #10 from Sardonyx001/feat/add-model-services
Browse files Browse the repository at this point in the history
feat: 各種モデルストアをアクセスするサービスを追加した
  • Loading branch information
Sardonyx001 authored Feb 29, 2024
2 parents a674482 + aeb4dc8 commit b6f0694
Show file tree
Hide file tree
Showing 27 changed files with 967 additions and 45 deletions.
38 changes: 38 additions & 0 deletions backend/config/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package config

import (
"os"

validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/golang-jwt/jwt/v4"
)

type AuthConfig struct {
AccessSecret string
RefreshSecret string
}

func LoadAuthConfig() AuthConfig {
return AuthConfig{
AccessSecret: os.Getenv("ACCESS_SECRET"),
RefreshSecret: os.Getenv("REFRESH_SECRET"),
}
}

type BasicAuth struct {
Username string `json:"username" validate:"required" example:"test_username"`
Password string `json:"password" validate:"required" example:"test_password"`
}

func (ba BasicAuth) Validate() error {
return validation.ValidateStruct(&ba,
validation.Field(&ba.Username, validation.Length(8, 255)),
validation.Field(&ba.Password, validation.Length(8, 255)),
)
}

type JwtCustomClaims struct {
ID string `json:"id"`
Admin bool `json:"admin"`
jwt.RegisteredClaims
}
2 changes: 2 additions & 0 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

type Config struct {
Auth AuthConfig
DB DBConfig
HTTP HTTPConfig
}
Expand All @@ -18,6 +19,7 @@ func NewConfig() *Config {
}

return &Config{
Auth: LoadAuthConfig(),
DB: LoadDBConfig(),
HTTP: LoadHTTPConfig(),
}
Expand Down
6 changes: 6 additions & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ require (
gorm.io/gorm v1.25.7
)

require github.com/golang-jwt/jwt/v4 v4.4.2

require go.uber.org/multierr v1.10.0 // indirect

require (
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
Expand All @@ -17,11 +21,13 @@ require (
github.com/jackc/pgx/v5 v5.4.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/labstack/echo-jwt v0.0.0-20221127215225-c84d41a71003
github.com/labstack/gommon v0.4.2
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.17.0
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead5
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
Expand All @@ -19,6 +21,8 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/labstack/echo-jwt v0.0.0-20221127215225-c84d41a71003 h1:FyalHKl9hnJvhNbrABJXXjC2hG7gvIF0ioW9i0xHNQU=
github.com/labstack/echo-jwt v0.0.0-20221127215225-c84d41a71003/go.mod h1:ovRFgyKvi73jQIFCWz9ByQwzhIyohkzY0MFAlPGyr8Q=
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
Expand All @@ -40,6 +44,10 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
Expand Down
44 changes: 44 additions & 0 deletions backend/logger/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package logger

import "go.uber.org/zap"

var zapLogger *zap.Logger

func New() error {
logger, err := zap.NewProduction()
if err != nil {
return err
}

zapLogger = logger

return nil
}

func Debug(msg string, fields ...zap.Field) {
zapLogger.Debug(msg, fields...)
}

func Info(msg string, fields ...zap.Field) {
zapLogger.Info(msg, fields...)
}

func Warn(msg string, fields ...zap.Field) {
zapLogger.Warn(msg, fields...)
}

func Error(msg string, fields ...zap.Field) {
zapLogger.Error(msg, fields...)
}

func Fatal(msg string, fields ...zap.Field) {
zapLogger.Fatal(msg, fields...)
}

func Sync() {
_ = zapLogger.Sync()
}

func Delete() {
zapLogger = nil
}
51 changes: 51 additions & 0 deletions backend/middlewares/auth_middleware.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package middlewares

import (
"backend/config"
"backend/stores"
"net/http"

"github.com/golang-jwt/jwt/v4"
"github.com/labstack/echo/v4"
)

type AuthMiddleware struct {
store *stores.Stores
}

func NewAuthMw(store *stores.Stores) AuthMiddleware {
return AuthMiddleware{
store: store,
}
}

func (m *AuthMiddleware) RestaurantAccess() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
restaurant_id := c.Param("restaurant_id")

token := c.Get("user").(*jwt.Token)
claims := token.Claims.(*config.JwtCustomClaims)

user, err := m.store.User.GetById(claims.ID)
if err != nil {
return echo.NewHTTPError(http.StatusUnauthorized, "Access Denied")
}

// UserがこのRestaurantにアクセスできる権限があるかどうかを確認
isOwner := false
for _, r := range user.Restaurants {
if restaurant_id == r.ID {
isOwner = true
break
}
}

if !isOwner {
return echo.NewHTTPError(http.StatusUnauthorized, "Access Denied")
}

return next(c)
}
}
}
3 changes: 1 addition & 2 deletions backend/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ type User struct {
UUIDBaseModel
Username string `json:"username" gorm:"unique; not null"`
PasswordHash string `json:"-" gorm:"not null"`
Status Status `json:"status" gorm:"not null"`
Status Status `json:"status" gorm:"default:'ACTIVE';not null"`
AdminID string `json:"-"`
Admin Admin `json:"-"`
Restaurants []*Restaurant `json:"restaurants" gorm:"many2many:user_restaurants;"`

}
67 changes: 67 additions & 0 deletions backend/server/handlers/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package handlers

import (
"backend/config"
"backend/services"
"backend/utils"
"net/http"

"github.com/labstack/echo/v4"
)

type (
AdminHandler interface {
GetAdminById(c echo.Context) error
CreateAdmin(c echo.Context) error
UpdateAdminById(c echo.Context) error
DeleteAdminById(c echo.Context) error
}

adminHandler struct {
services.AdminService
}
)

func (h *adminHandler) GetAdminById(c echo.Context) error {
userID := c.Param("id")
user, err := h.AdminService.GetAdminById(userID)
if err != nil {

return c.JSON(http.StatusNotFound, utils.Error{Message: err.Error()})
}
return c.JSON(http.StatusOK, user)
}

func (h *adminHandler) CreateAdmin(c echo.Context) error {
userAuth := new(config.BasicAuth)

if err := c.Bind(userAuth); err != nil {
return c.JSON(http.StatusBadRequest, "Request doesn't match schema")
}

if err := userAuth.Validate(); err != nil {
return c.JSON(http.StatusBadRequest, "Required fields are empty or not valid")
}

_, err := h.AdminService.GetAdminByUsername(userAuth.Username)

if err == nil {
return c.JSON(http.StatusBadRequest, "User already exists")
}

userId, err := h.AdminService.CreateAdmin(userAuth)
if err != nil {
return c.JSON(http.StatusInternalServerError, "Server error")
}

return c.JSON(http.StatusCreated, userId)

}

func (h *adminHandler) UpdateAdminById(c echo.Context) error {
return c.JSON(http.StatusOK, "UpdateUserById")
}

func (h *adminHandler) DeleteAdminById(c echo.Context) error {
return c.JSON(http.StatusOK, "Called DeleteUserById")
}
79 changes: 79 additions & 0 deletions backend/server/handlers/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package handlers

import (
"backend/config"
"backend/logger"
"backend/services"
"net/http"

"github.com/labstack/echo/v4"
"go.uber.org/zap"
"golang.org/x/crypto/bcrypt"
)

type (
AuthHandler interface {
LoginForUser(c echo.Context) error
LoginForAdmin(c echo.Context) error
}

authHandler struct {
services.AuthService
services.UserService
services.AdminService
}
)

func (h *authHandler) LoginForUser(c echo.Context) error {
userAuth := new(config.BasicAuth)

if err := c.Bind(userAuth); err != nil {
return c.JSON(http.StatusBadRequest, "Request doesn't match schema")
}

if err := userAuth.Validate(); err != nil {
return c.JSON(http.StatusBadRequest, "Required fields are empty or not valid")
}

user, err := h.UserService.GetUserByUsername(userAuth.Username)
if err != nil || (bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(userAuth.Password)) != nil) {
return c.JSON(http.StatusUnauthorized, "Invalid credentials")
}

accessToken, _, err := h.AuthService.GenerateAccessToken(user.ID, false)
if err != nil {
logger.Error("Failed to authenticate: ", zap.Error(err))
return c.JSON(http.StatusUnauthorized, "Invalid credentials")
}

return c.JSON(http.StatusOK, map[string]string{
"token": accessToken,
})
}

func (h *authHandler) LoginForAdmin(c echo.Context) error {
userAuth := new(config.BasicAuth)

if err := c.Bind(userAuth); err != nil {
return c.JSON(http.StatusBadRequest, "Request doesn't match schema")
}

if err := userAuth.Validate(); err != nil {
return c.JSON(http.StatusBadRequest, "Required fields are empty or not valid")
}

admin, err := h.AdminService.GetAdminByUsername(userAuth.Username)
if err != nil || (bcrypt.CompareHashAndPassword([]byte(admin.PasswordHash), []byte(userAuth.Password)) != nil) {
return c.JSON(http.StatusUnauthorized, "Invalid credentials")
}

accessToken, _, err := h.AuthService.GenerateAccessToken(admin.ID, true)
if err != nil {
logger.Error("Failed to authenticate: ", zap.Error(err))
return c.JSON(http.StatusUnauthorized, "Invalid credentials")
}

return c.JSON(http.StatusOK, map[string]string{
"token": accessToken,
})
}
Loading

0 comments on commit b6f0694

Please sign in to comment.