Если вы видите что-то необычное, просто сообщите мне. Skip to main content

Echo framework + GORM = Огненно быстрое Golang приложение на стороне сервера. Пример аутентификации.

InВ thisстатье, articleя Iхочу wantпоказать toпример showреализации exampleвхода, ofвыхода login,и logoutрегистрации and registration implementation usingиспользуя Go фреймворк Echo frameworkи andGorm GORMдля (GopostgreSQL. ObjectДля Relationalаутентификации Mapper)пользователей withбудет PostgreSQL.использоваться WeJWT(Json useweb JWT (JSON Web Token) to authenticate userstoken).

FirstlyДля weначала createсоздадим main.go:go:

package main

import (
	"app1/helper"
	"app1/models"
	"fmt"
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

func main() {
	configuration := helper.GetConfig()

	gormParameters := fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s sslmode=disable", configuration.DbHost, configuration.DbPort, configuration.DbName, configuration.DbUsername, configuration.DbPassword)
	gormDB, err := gorm.Open("postgres", gormParameters)
	if err != nil {
		panic("failed to connect database")
	}
	helper.GormDB = gormDB

	// Migrate the schema (tables): User, Authentication
	helper.GormDB.AutoMigrate(&helper.User{})
	helper.GormDB.AutoMigrate(&helper.Authentication{})
	helper.GormDB.Model(&helper.Authentication{}).AddForeignKey("user_id", "users(id)", "CASCADE", "CASCADE")

	echoFramework := echo.New()
	echoFramework.Use(middleware.Logger()) // log
	echoFramework.Use(middleware.CORS())   // CORS from Any Origin, Any Method

	echoGroupUseJWT := echoFramework.Group("/api/v1")
echoGroupUseJWT.Use(middleware.JWT([]byte(configuration.EncryptionKey)))
	echoGroupNoJWT := echoFramework.Group("/api/v1")

	// /api/v1/users : logged in users
	echoGroupUseJWT.POST("/users/logout", models.Logout)

	// /api/v1/users : public accessible
	echoGroupNoJWT.POST("/users", models.CreateUser)
	echoGroupNoJWT.POST("/users/login", models.Login)

	defer helper.GormDB.Close()
	echoFramework.Logger.Fatal(echoFramework.Start(":1323"))
}

SecondlyВторое we- createсоздадим globals.go:go:

package helper

import (
	"regexp"
	"time"
	"github.com/jinzhu/gorm"

)

type Configuration struct {
	EncryptionKey string
	DbHost        string
	DbPort        string
	DbName        string
	DbUsername    string
	DbPassword    string
}

var configuration Configuration
type ModelBase struct {
	ID        int       `gorm:"primary_key"`
	CreatedAt time.Time `json:"-"`
	UpdatedAt time.Time `json:"-"`
}

type User struct {
	ModelBase        // replaces gorm.Model
	Email     string `gorm:"not null; unique"`
	Password  string `gorm:"not null" json:"-"`
	Name      string `gorm:"not null; type:varchar(100)"` // unique_index
}

type Authentication struct {
	ModelBase
	User   User `gorm:"foreignkey:UserID; not null"`
	UserID int
	Token  string `gorm:"type:varchar(200); not null"`
}

type CustomHTTPSuccess struct {
	Data string `json:"data"`
}

type ErrorType struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

type CustomHTTPError struct {
	Error ErrorType `json:"error"`
}

var GormDB *gorm.DB
func init() {
	configuration = Configuration{
		EncryptionKey: "F61L8L7CUCGN0NK6336I8TFP9Y2ZOS43",
		DbHost:        "localhost",
		DbPort:        "5432",
		DbName:        "postgres",
		DbUsername:    "postgres",
		DbPassword:    "postgres",
	}
}

func GetConfig() Configuration {
	return configuration
}

func ValidateEmail(email string) (matchedString bool) {
	re := regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
	matchedString = re.MatchString(email)
	return
}

FinallyТеперь ourреализуем implementationметод ofаутентификации theв authentication methods in user.go:go:

package models

import (
	"app1/helper"
	"fmt"
	"net/http"
	"strconv"
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/labstack/echo"
)

func CreateUser(c echo.Context) error {
	m := echo.Map{}
	if err := c.Bind(&m); err != nil {
		// return err
	}

	name := m["name"].(string)
	email := m["email"].(string)
	password := m["password"].(string)
	confirmPassword := m["confirm_password"].(string)
	if password == "" || confirmPassword == "" || name == "" || email == "" {
		return echo.NewHTTPError(http.StatusBadRequest, "Please enter name, email and password")
	}
	if password != confirmPassword {
		return echo.NewHTTPError(http.StatusBadRequest, "Confirm password is not same to password provided")
	}
	if helper.ValidateEmail(email) == false {
		return echo.NewHTTPError(http.StatusBadRequest, "Please enter valid email")
	}
	if bCheckUserExists(email) == true {
		return echo.NewHTTPError(http.StatusBadRequest, "Email provided already exists")
	}
	configuration := helper.GetConfig()
	enc, _ := helper.EncryptString(password, configuration.EncryptionKey)
	user1 := helper.User{Name: name, Email: email, Password: enc}
  
	// globals.GormDB.NewRecord(user) // => returns `true` as primary key is blank
	helper.GormDB.Create(&user1)
	token := jwt.New(jwt.SigningMethodHS256)
	claims := token.Claims.(jwt.MapClaims)
	claims["name"] = user1.Name
	claims["email"] = user1.Email
	t, err := token.SignedString([]byte(configuration.EncryptionKey)) // "secret" >> EncryptionKey
	if err != nil {
		return err
	}
	authentication := helper.Authentication{}
	if helper.GormDB.First(&authentication, "user_id =?", user1.ID).RecordNotFound() {
		// insert
		helper.GormDB.Create(&helper.Authentication{User: user1, Token: t})
	} else {
		authentication.User = user1
		authentication.Token = t
		helper.GormDB.Save(&authentication)
	}
	return c.JSON(http.StatusOK, map[string]string{
		"token": t,
	})
}
func bCheckUserExists(email string) bool {
	user1 := helper.User{}
	if helper.GormDB.Where(&helper.User{Email: email}).First(&user1).RecordNotFound() {
		return false
	}
	return true
}
func ValidateUser(email, password string, c echo.Context) (bool, error) {
	fmt.Println("validate")
	var user1 helper.User
	if helper.GormDB.First(&user1, "email =?", email).RecordNotFound() {
		return false, nil
	}
	configuration := helper.GetConfig()
	decrypted, _ := helper.DecryptString(user1.Password, configuration.EncryptionKey)
	if password == decrypted {
		return true, nil
	}
	return false, nil
}

func Login(c echo.Context) error {
	m := echo.Map{}
	if err := c.Bind(&m); err != nil {
		// return err
	}
	email := m["email"].(string)
	password := m["password"].(string)
	var user1 helper.User
	if helper.GormDB.First(&user1, "email =?", email).RecordNotFound() {
		_error := helper.CustomHTTPError{
			Error: helper.ErrorType{
				Code:    http.StatusBadRequest,
				Message: "Invalid email & password",
			},
		}
		return c.JSONPretty(http.StatusBadGateway, _error, "  ")
	}
	configuration := helper.GetConfig()
	decrypted, _ := helper.DecryptString(user1.Password, configuration.EncryptionKey)
	if password == decrypted {
		token := jwt.New(jwt.SigningMethodHS256)
		claims := token.Claims.(jwt.MapClaims)
		claims["name"] = user1.Name
		claims["email"] = user1.Email
		claims["id"] = user1.ModelBase.ID
		t, err := token.SignedString([]byte(configuration.EncryptionKey)) // "secret" >> EncryptionKey
		if err != nil {
			return err
		}
		authentication := helper.Authentication{}
		if helper.GormDB.First(&authentication, "user_id =?", user1.ID).RecordNotFound() {
			// insert
			helper.GormDB.Create(&helper.Authentication{User: user1, Token: t})
		} else {
			// update
			authentication.User = user1
			authentication.Token = t
			helper.GormDB.Save(&authentication)
		}
		return c.JSON(http.StatusOK, map[string]string{
			"token": t,
		})
	} else {
		_error := helper.CustomHTTPError{
			Error: helper.ErrorType{
				Code:    http.StatusBadRequest,
				Message: "Invalid email & password",
			},
		}
		return c.JSONPretty(http.StatusBadGateway, _error, "  ")
	}
}
func Logout(c echo.Context) error {
	tokenRequester := c.Get("user").(*jwt.Token)
	claims := tokenRequester.Claims.(jwt.MapClaims)
	fRequesterID := claims["id"].(float64)
	iRequesterID := int(fRequesterID)
	sRequesterID := strconv.Itoa(iRequesterID)
	requester := helper.User{}
	if helper.GormDB.First(&requester, "id =?", sRequesterID).RecordNotFound() {
		return echo.ErrUnauthorized
	}
	authentication := helper.Authentication{}
	if helper.GormDB.First(&authentication, "user_id =?", requester.ModelBase.ID).RecordNotFound() {
		return echo.ErrUnauthorized
	}
	helper.GormDB.Delete(&authentication)
	return c.String(http.StatusAccepted, "")
}

EncryptionПропущенный andфункции decryptionшифроки\расшифровки. functionsНапишите areмне missing.чтобы Dropих me an email to get themувидеть.