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увидеть.