fix(service): remove duplicated auth service and use it in both of admin and benefactor side

This commit is contained in:
Masood Keshvari 2024-01-25 15:13:39 +03:30
parent aa129a870e
commit bbc31ee48f
24 changed files with 77 additions and 151 deletions

View File

@ -4,8 +4,7 @@ import (
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider/kavenegar"
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
adminauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/admin"
benefactorauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
)
@ -16,8 +15,8 @@ type HTTPServer struct {
type Config struct {
HTTPServer HTTPServer `koanf:"http_server"`
Mysql mysql.Config `koanf:"mysql"`
Auth benefactorauthservice.Config `koanf:"auth"`
AdminAuth adminauthservice.Config `koanf:"admin_auth"`
Auth authservice.Config `koanf:"auth"`
AdminAuth authservice.Config `koanf:"admin_auth"`
Redis redis.Config `koanf:"redis"`
KavenegarSmsProvider smsprovider.Config `koanf:"kavenegar_sms_provider"`
BenefactorSvc benefactorservice.Config `koanf:"benefactor_service"`

View File

@ -1,7 +1,7 @@
package config
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
)
@ -13,6 +13,12 @@ func Default() Config {
AccessSubject: AccessTokenSubject,
RefreshSubject: RefreshTokenSubject,
},
AdminAuth: authservice.Config{
AccessExpirationTime: AccessTokenExpireDuration,
RefreshExpirationTime: RefreshTokenExpireDuration,
AccessSubject: AccessTokenSubject,
RefreshSubject: RefreshTokenSubject,
},
BenefactorSvc: benefactorservice.Config{
OtpChars: OtpChars,

View File

@ -2,7 +2,7 @@ package adminhandler
import (
adminservice "git.gocasts.ir/ebhomengo/niki/service/admin/admin"
adminauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/admin"
adminauthservice "git.gocasts.ir/ebhomengo/niki/service/auth"
adminvalidator "git.gocasts.ir/ebhomengo/niki/validator/admin/admin"
)

View File

@ -1,6 +1,9 @@
package adminhandler
import "github.com/labstack/echo/v4"
import (
"git.gocasts.ir/ebhomengo/niki/delivery/http_server/middleware"
"github.com/labstack/echo/v4"
)
func (h Handler) SetRoutes(e *echo.Echo) {
r := e.Group("/admins")
@ -9,6 +12,7 @@ func (h Handler) SetRoutes(e *echo.Echo) {
//r.POST("/", h.Add).Name = "admin-addkindboxreq"
r.POST("/register", h.Register)
r.POST("/login-by-phone", h.LoginByPhoneNumber)
r.GET("/test", h.LoginByPhoneNumber, middleware.Auth(h.authSvc, h.authConfig))
//nolint:gocritic
//r.PATCH("/:id", h.Update).Name = "admin-updatekindboxreq"
}

View File

@ -2,7 +2,7 @@ package adminkindboxhandler
import (
adminkindboxservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
adminkindboxvalidator "git.gocasts.ir/ebhomengo/niki/validator/admin/kind_box"
)

View File

@ -2,7 +2,7 @@ package adminkindboxreqhandler
import (
adminkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box_req"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
adminkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/admin/kind_box_req"
)

View File

@ -1,7 +1,7 @@
package benefactoraddresshandler
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactoraddressservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/address"
benefactoraddressvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/address"
)

View File

@ -1,7 +1,7 @@
package benefactorhandler
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
benefactorvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/benefactor"
)

View File

@ -1,7 +1,7 @@
package benefactorkindboxhandler
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactorkindboxservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box"
benefactorkindboxvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box"
)

View File

@ -1,7 +1,7 @@
package benefactorkindboxreqhandler
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactorkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box_req"
benefactorkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box_req"
)

View File

@ -2,7 +2,7 @@ package middleware
import (
"git.gocasts.ir/ebhomengo/niki/config"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
mw "github.com/labstack/echo-jwt/v4"
"github.com/labstack/echo/v4"
)

View File

@ -13,7 +13,7 @@ func BenefactorAuthorization(role entity.UserRole) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
claims := claim.GetClaimsFromEchoContext(c)
if claims.Role != role {
if claims.Role != role.String() {
return c.JSON(http.StatusForbidden, echo.Map{"message": errmsg.ErrorMsgUserNotAllowed})
}

View File

@ -9,8 +9,7 @@ import (
benefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/benefactor"
benefactorkindboxreqhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/kind_box_req"
adminservice "git.gocasts.ir/ebhomengo/niki/service/admin/admin"
adminauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/admin"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactoraddressservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/address"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
benefactorkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box_req"
@ -35,21 +34,21 @@ func New(
cfg config.Config,
benefactorSvc benefactorservice.Service,
benefactorVld benefactorvalidator.Validator,
authSvc authservice.Service,
benefactorAuthSvc authservice.Service,
benefactorKindBoxReqSvc benefactorkindboxreqservice.Service,
benefactorKindBoxReqVld benefactorkindboxreqvalidator.Validator,
benefactorAddressSvc benefactoraddressservice.Service,
benefactorAddressVld benefactoraddressvalidator.Validator,
adminSvc adminservice.Service,
adminVld adminvalidator.Validator,
adminAuthSvc adminauthservice.Service,
adminAuthSvc authservice.Service,
) Server {
return Server{
Router: echo.New(),
config: cfg,
benefactorHandler: benefactorhandler.New(cfg.Auth, authSvc, benefactorSvc, benefactorVld),
benefactorKindBoxReqHandler: benefactorkindboxreqhandler.New(cfg.Auth, authSvc, benefactorKindBoxReqSvc, benefactorKindBoxReqVld),
benefactorAddressHandler: benefactoraddresshandler.New(cfg.Auth, authSvc, benefactorAddressSvc, benefactorAddressVld),
benefactorHandler: benefactorhandler.New(cfg.Auth, benefactorAuthSvc, benefactorSvc, benefactorVld),
benefactorKindBoxReqHandler: benefactorkindboxreqhandler.New(cfg.Auth, benefactorAuthSvc, benefactorKindBoxReqSvc, benefactorKindBoxReqVld),
benefactorAddressHandler: benefactoraddresshandler.New(cfg.Auth, benefactorAuthSvc, benefactorAddressSvc, benefactorAddressVld),
adminHandler: adminhandler.New(cfg.AdminAuth, adminAuthSvc, adminSvc, adminVld),
}
}

6
entity/authenticable.go Normal file
View File

@ -0,0 +1,6 @@
package entity
type Authenticable struct {
ID uint
Role string
}

19
main.go
View File

@ -14,8 +14,7 @@ import (
mysqlkindboxreq "git.gocasts.ir/ebhomengo/niki/repository/mysql/kind_box_req"
redisotp "git.gocasts.ir/ebhomengo/niki/repository/redis/redis_otp"
adminservice "git.gocasts.ir/ebhomengo/niki/service/admin/admin"
adminauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/admin"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
benefactoraddressservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/address"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
benefactorkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box_req"
@ -32,22 +31,22 @@ func main() {
mgr := migrator.New(cfg.Mysql)
mgr.Up()
authSvc, benefactorSvc, benefactorVld, benefactorKindBoxReqSvc, benefactorKindBoxReqVld, benefactorAddressSvc, benefactorAddressVld,
benefactorAuthSvc, benefactorSvc, benefactorVld, benefactorKindBoxReqSvc, benefactorKindBoxReqVld, benefactorAddressSvc, benefactorAddressVld,
adminSvc, adminVld, adminAuthSvc := setupServices(cfg)
server := httpserver.New(cfg, benefactorSvc, benefactorVld, authSvc, benefactorKindBoxReqSvc, benefactorKindBoxReqVld,
server := httpserver.New(cfg, benefactorSvc, benefactorVld, benefactorAuthSvc, benefactorKindBoxReqSvc, benefactorKindBoxReqVld,
benefactorAddressSvc, benefactorAddressVld, adminSvc, adminVld, adminAuthSvc)
server.Serve()
}
//nolint:nakedret,gocritic // we are sure of this
func setupServices(cfg config.Config) (
authSvc authservice.Service, benefactorSvc benefactorservice.Service, benefactorVld benefactorvalidator.Validator,
benefactorAuthSvc authservice.Service, benefactorSvc benefactorservice.Service, benefactorVld benefactorvalidator.Validator,
benefactorKindBoxReqSvc benefactorkindboxreqservice.Service, benefactorKindBoxReqVld benefactorkindboxreqvalidator.Validator,
benefactorAddressSvc benefactoraddressservice.Service,
benefactorAddressVld benefactoraddressvalidator.Validator,
adminSvc adminservice.Service, adminVld adminvalidator.Validator, adminAuthSvc adminauthservice.Service,
adminSvc adminservice.Service, adminVld adminvalidator.Validator, adminAuthSvc authservice.Service,
) {
authSvc = authservice.New(cfg.Auth)
benefactorAuthSvc = authservice.New(cfg.Auth)
MysqlRepo := mysql.New(cfg.Mysql)
@ -56,8 +55,8 @@ func setupServices(cfg config.Config) (
benefactorMysql := mysqlbenefactor.New(MysqlRepo)
kavenegarSmsProvider := smsprovider.New(cfg.KavenegarSmsProvider)
otpSmsProvider := kavenegarotp.New(kavenegarSmsProvider)
authGenerator := authservice.New(cfg.Auth)
benefactorSvc = benefactorservice.New(cfg.BenefactorSvc, RedisOtp, otpSmsProvider, authGenerator, benefactorMysql)
benefactorSvc = benefactorservice.New(cfg.BenefactorSvc, RedisOtp, otpSmsProvider, benefactorAuthSvc, benefactorMysql)
benefactorAddressMysql := mysqladdress.New(MysqlRepo)
benefactorAddressSvc = benefactoraddressservice.New(benefactorAddressMysql)
benefactorAddressVld = benefactoraddressvalidator.New(benefactorSvc, benefactorAddressMysql)
@ -67,7 +66,7 @@ func setupServices(cfg config.Config) (
benefactorKindBoxReqSvc = benefactorkindboxreqservice.New(benefactorKindBoxReqMysql)
benefactorKindBoxReqVld = benefactorkindboxreqvalidator.New(benefactorKindBoxReqMysql, benefactorSvc, benefactorAddressSvc)
adminAuthSvc = adminauthservice.New(cfg.AdminAuth)
adminAuthSvc = authservice.New(cfg.AdminAuth)
adminMysql := mysqladmin.New(MysqlRepo)
adminVld = adminvalidator.New(adminMysql)
adminSvc = adminservice.New(adminMysql, adminAuthSvc)

View File

@ -2,7 +2,7 @@ package claim
import (
"git.gocasts.ir/ebhomengo/niki/config"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth"
"github.com/labstack/echo/v4"
)

View File

@ -3,6 +3,7 @@ package adminservice
import (
"context"
"git.gocasts.ir/ebhomengo/niki/entity"
adminserviceparam "git.gocasts.ir/ebhomengo/niki/param/admin/admin"
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
@ -19,13 +20,16 @@ func (s Service) LoginWithPhoneNumber(ctx context.Context, req adminserviceparam
if cErr := CompareHash(admin.GetPassword(), req.Password); cErr != nil {
return adminserviceparam.LoginWithPhoneNumberResponse{}, richerror.New(op).WithErr(cErr).WithMessage(errmsg.ErrorMsgPhoneNumberOrPassIsIncorrect).WithKind(richerror.KindForbidden)
}
accessToken, aErr := s.auth.CreateAccessToken(admin)
authenticableAdmin := entity.Authenticable{
ID: admin.ID,
Role: admin.Role.String(),
}
accessToken, aErr := s.auth.CreateAccessToken(authenticableAdmin)
if aErr != nil {
return adminserviceparam.LoginWithPhoneNumberResponse{}, richerror.New(op).WithErr(aErr).WithKind(richerror.KindUnexpected)
}
refreshToken, rErr := s.auth.CreateRefreshToken(admin)
refreshToken, rErr := s.auth.CreateRefreshToken(authenticableAdmin)
if rErr != nil {
return adminserviceparam.LoginWithPhoneNumberResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
}

View File

@ -10,8 +10,8 @@ import (
)
type AuthGenerator interface {
CreateAccessToken(benefactor entity.Admin) (string, error)
CreateRefreshToken(benefactor entity.Admin) (string, error)
CreateAccessToken(benefactor entity.Authenticable) (string, error)
CreateRefreshToken(benefactor entity.Authenticable) (string, error)
}
type Repository interface {

View File

@ -1,16 +0,0 @@
package benefactorauthservice
import (
"git.gocasts.ir/ebhomengo/niki/entity"
"github.com/golang-jwt/jwt/v4"
)
type Claims struct {
jwt.RegisteredClaims
UserID uint `json:"user_id"`
Role entity.UserRole `json:"role"`
}
func (c Claims) Valid() error {
return c.RegisteredClaims.Valid()
}

View File

@ -1,78 +0,0 @@
package benefactorauthservice
import (
"strings"
"time"
"git.gocasts.ir/ebhomengo/niki/entity"
"github.com/golang-jwt/jwt/v4"
)
type Config struct {
SignKey string `koanf:"sign_key"`
AccessExpirationTime time.Duration `koanf:"access_expiration_time"`
RefreshExpirationTime time.Duration `koanf:"refresh_expiration_time"`
AccessSubject string `koanf:"access_subject"`
RefreshSubject string `koanf:"refresh_subject"`
}
type Service struct {
config Config
}
func New(cfg Config) Service {
return Service{
config: cfg,
}
}
func (s Service) CreateAccessToken(benefactor entity.Benefactor) (string, error) {
return s.createToken(benefactor.ID, benefactor.Role, s.config.AccessSubject, s.config.AccessExpirationTime)
}
func (s Service) CreateRefreshToken(benefactor entity.Benefactor) (string, error) {
return s.createToken(benefactor.ID, benefactor.Role, s.config.RefreshSubject, s.config.RefreshExpirationTime)
}
func (s Service) ParseToken(bearerToken string) (*Claims, error) {
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
tokenStr := strings.Replace(bearerToken, "Bearer ", "", 1)
token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(s.config.SignKey), nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, err
}
func (s Service) createToken(userID uint, role entity.UserRole, subject string, expireDuration time.Duration) (string, error) {
// create a signer for rsa 256
// TODO - replace with rsa 256 RS256 - https://github.com/golang-jwt/jwt/blob/main/http_example_test.go
// set our claims
claims := Claims{
RegisteredClaims: jwt.RegisteredClaims{
Subject: subject,
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
},
UserID: userID,
Role: role,
}
// TODO - add sign method to config
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := accessToken.SignedString([]byte(s.config.SignKey))
if err != nil {
return "", err
}
return tokenString, nil
}

View File

@ -1,14 +1,13 @@
package adminauthservice
package auth
import (
"git.gocasts.ir/ebhomengo/niki/entity"
"github.com/golang-jwt/jwt/v4"
)
type Claims struct {
jwt.RegisteredClaims
UserID uint `json:"user_id"`
Role entity.AdminRole `json:"role"`
Role string `json:"role"`
}
func (c Claims) Valid() error {

View File

@ -1,4 +1,4 @@
package adminauthservice
package auth
import (
"strings"
@ -26,12 +26,12 @@ func New(cfg Config) Service {
}
}
func (s Service) CreateAccessToken(admin entity.Admin) (string, error) {
return s.createToken(admin.ID, admin.Role, s.config.AccessSubject, s.config.AccessExpirationTime)
func (s Service) CreateAccessToken(user entity.Authenticable) (string, error) {
return s.createToken(user.ID, user.Role, s.config.AccessSubject, s.config.AccessExpirationTime)
}
func (s Service) CreateRefreshToken(admin entity.Admin) (string, error) {
return s.createToken(admin.ID, admin.Role, s.config.RefreshSubject, s.config.RefreshExpirationTime)
func (s Service) CreateRefreshToken(user entity.Authenticable) (string, error) {
return s.createToken(user.ID, user.Role, s.config.RefreshSubject, s.config.RefreshExpirationTime)
}
func (s Service) ParseToken(bearerToken string) (*Claims, error) {
@ -53,7 +53,7 @@ func (s Service) ParseToken(bearerToken string) (*Claims, error) {
return nil, err
}
func (s Service) createToken(userID uint, role entity.AdminRole, subject string, expireDuration time.Duration) (string, error) {
func (s Service) createToken(userID uint, role, subject string, expireDuration time.Duration) (string, error) {
// create a signer for rsa 256
// TODO - replace with rsa 256 RS256 - https://github.com/golang-jwt/jwt/blob/main/http_example_test.go

View File

@ -42,12 +42,16 @@ func (s Service) LoginOrRegister(ctx context.Context, req benefactoreparam.Login
benefactor = newBenefactor
}
accessToken, aErr := s.auth.CreateAccessToken(benefactor)
athenticableBenefactor := entity.Authenticable{
ID: benefactor.ID,
Role: benefactor.Role.String(),
}
accessToken, aErr := s.auth.CreateAccessToken(athenticableBenefactor)
if aErr != nil {
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(aErr).WithKind(richerror.KindUnexpected)
}
refreshToken, rErr := s.auth.CreateRefreshToken(benefactor)
refreshToken, rErr := s.auth.CreateRefreshToken(athenticableBenefactor)
if rErr != nil {
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
}

View File

@ -20,8 +20,8 @@ type Repository interface {
}
type AuthGenerator interface {
CreateAccessToken(benefactor entity.Benefactor) (string, error)
CreateRefreshToken(benefactor entity.Benefactor) (string, error)
CreateAccessToken(benefactor entity.Authenticable) (string, error)
CreateRefreshToken(benefactor entity.Authenticable) (string, error)
}
type RedisOtp interface {