16. Registration center-consul

1. Service Registration and Discovery

  • What is service registration and discovery : If this product is already running online, and one day the operation wants to hold a promotional event, then our corresponding [User Service] may need to open three new microservice instances to support this promotional event . At the same time, as a hard-working programmer, you have to manually add the ip and port of the three newly added microservice instances to the API gateway. A truly online microservice system may have hundreds or thousands of microservices. Do I have to manually add them one by one?
  • Solution : When we add a new microservice instance, the microservice will send its ip and port to the registration center and record them in the registration center. When the API gateway needs to access some microservices, it will go to the registration center to obtain the corresponding ip and port. thereby enabling automated operation

insert image description here

  • Technology selection : Consul compared with other common service discovery frameworks

insert image description here


Two, consul installation and configuration


3. Consul service registration and cancellation

1 - Registration Services

insert image description here
insert image description here

2 - Logout service

3 - Health Check

4 - Get Services


4. Use consul in go

  • Register : registration service
  • AllServices : get all services
  • FilterService : filter service
package main

import (
	"fmt"
	"github.com/hashicorp/consul/api"
)

// Register 注册服务
func Register(address string, port int, name string, tags []string, id string) error {
    
    
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.124.51:8500"

	client, err := api.NewClient(cfg)
	if err != nil {
    
    
		panic(err)
	}
	//生成对应的检查对象
	check := &api.AgentServiceCheck{
    
    
		HTTP:                           "http://192.168.124.9:8081/health",
		Timeout:                        "5s",
		Interval:                       "5s",
		DeregisterCriticalServiceAfter: "10s",
	}

	//生成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = name
	registration.ID = id
	registration.Port = port
	registration.Tags = tags
	registration.Address = address
	registration.Check = check

	err = client.Agent().ServiceRegister(registration)
	if err != nil {
    
    
		panic(err)
	}
	return nil
}

// AllServices 获取所有服务
func AllServices() {
    
    
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.124.51:8500"

	client, err := api.NewClient(cfg)
	if err != nil {
    
    
		panic(err)
	}

	data, err := client.Agent().Services()
	if err != nil {
    
    
		panic(err)
	}
	for key, _ := range data {
    
    
		fmt.Println(key)
	}
}

// FilterService 服务过滤
func FilterService() {
    
    
	cfg := api.DefaultConfig()
	cfg.Address = "192.168.124.51:8500"

	client, err := api.NewClient(cfg)
	if err != nil {
    
    
		panic(err)
	}

	data, err := client.Agent().ServicesWithFilter(`Service == "user-web"`)
	if err != nil {
    
    
		panic(err)
	}
	for key, _ := range data {
    
    
		fmt.Println(key)
	}
}

func main() {
    
    
	_ = Register("http://192.168.124.9", 8081, "user-web", []string{
    
    "mxshop", "bobby"}, "user-web")
	AllServices()
	FilterService()
}


Five, user_srv integrates viper and zap

  • user_srv/config/config.go : add configuration
package config

type MysqlConfig struct {
    
    
	Host     string `mapstructure:"host" json:"host"`
	Port     int    `mapstructure:"port" json:"port"`
	Name     string `mapstructure:"db" json:"db"`
	User     string `mapstructure:"user" json:"user"`
	Password string `mapstructure:"password" json:"password"`
}

type ServerConfig struct {
    
    
	Name      string      `mapstructure:"name" json:"name"`
	MysqlInfo MysqlConfig `mapstructure:"mysql" json:"mysql"`
}

  • user_srv/global/global.go : add global object ServerConfig
package global

import (
	"gorm.io/gorm"
	"nd/user_srv/config"
)

var (
	DB           *gorm.DB
	ServerConfig config.ServerConfig
)

  • user_srv/initialize/init_config.go : Initialize config configuration
package initialize

import (
	"fmt"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"nd/user_srv/global"
)

func GetEnvInfo(env string) bool {
    
    
	viper.AutomaticEnv()
	return viper.GetBool(env)
	//刚才设置的环境变量 想要生效 我们必须得重启goland
}

func InitConfig() {
    
    
	//从配置文件中读取出对应的配置
	debug := GetEnvInfo("DEV_CONFIG")
	configFilePrefix := "config"
	configFileName := fmt.Sprintf("%s_pro.yaml", configFilePrefix)
	if debug {
    
    
		configFileName = fmt.Sprintf("%s_debug.yaml", configFilePrefix)
	}

	v := viper.New()
	//文件的路径如何设置
	v.SetConfigFile(configFileName)
	if err := v.ReadInConfig(); err != nil {
    
    
		panic(err)
	}
	//这个对象如何在其他文件中使用 - 全局变量
	if err := v.Unmarshal(&global.ServerConfig); err != nil {
    
    
		panic(err)
	}
	zap.S().Infof("配置信息: %v", global.ServerConfig)
}

  • user_srv/initialize/init_db.go : initialize db
package initialize

import (
	"fmt"
	"log"
	"os"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"

	"nd/user_srv/global"
)

func InitDB() {
    
    
	c := global.ServerConfig.MysqlInfo
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		c.User, c.Password, c.Host, c.Port, c.Name)
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
    
    
			SlowThreshold: time.Second,   // 慢 SQL 阈值
			LogLevel:      logger.Silent, // Log level
			Colorful:      true,          // 禁用彩色打印
		},
	)

	// 全局模式
	var err error
	global.DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
    
    
		NamingStrategy: schema.NamingStrategy{
    
    
			SingularTable: true,
		},
		Logger: newLogger,
	})
	if err != nil {
    
    
		panic(err)
	}
}

  • user_srv\initialize\init_logger.go : zap initialization
package initialize

import "go.uber.org/zap"

func InitLogger() {
    
    
	logger, _ := zap.NewDevelopment()
	zap.ReplaceGlobals(logger)
}

  • yaml
//user_srv/config_pro.yaml
mysql:
  host: '192.168.124.51'
  port: '3306'
  user: 'root'
  password: 'jiushi'
  db: 'mxshop_user_srv'
//user_srv/config_pro.yaml
mysql:
  host: '192.168.124.51'
  port: '3306'
  user: 'root'
  password: 'jiushi'
  db: 'mxshop_user_srv'
  • user_srv/main.go : main logic modification
package main

import (
	"flag"
	"fmt"
	"go.uber.org/zap"
	"nd/user_srv/global"
	"nd/user_srv/handler"
	"nd/user_srv/initialize"
	"nd/user_srv/proto"
	"net"

	"google.golang.org/grpc"
)

func main() {
    
    
	IP := flag.String("ip", "0.0.0.0", "ip地址")
	Port := flag.Int("port", 50051, "端口号")

	//初始化
	initialize.InitLogger()
	initialize.InitConfig()
	initialize.InitDB()
	zap.S().Info(global.ServerConfig)

	flag.Parse()
	zap.S().Info("ip: ", *IP)
	zap.S().Info("port: ", *Port)

	server := grpc.NewServer()
	proto.RegisterUserServer(server, &handler.UserServer{
    
    })
	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *IP, *Port))
	if err != nil {
    
    
		panic("failed to listen:" + err.Error())
	}
	err = server.Serve(lis)
	if err != nil {
    
    
		panic("failed to start grpc:" + err.Error())
	}
}

6. grpc health check

Register the grpc service to consul

  • user_srv/config/config.go : add ConsulConfig configuration object
package config

type MysqlConfig struct {
    
    
	Host     string `mapstructure:"host" json:"host"`
	Port     int    `mapstructure:"port" json:"port"`
	Name     string `mapstructure:"db" json:"db"`
	User     string `mapstructure:"user" json:"user"`
	Password string `mapstructure:"password" json:"password"`
}

type ConsulConfig struct {
    
    
	Host string `mapstructure:"host" json:"host"`
	Port int    `mapstructure:"port" json:"port"`
}

type ServerConfig struct {
    
    
	Name       string       `mapstructure:"name" json:"name"`
	MysqlInfo  MysqlConfig  `mapstructure:"mysql" json:"mysql"`
	ConsulInfo ConsulConfig `mapstructure:"consul" json:"consul"`
}

  • yaml
//user_srv/config_pro.yaml
mysql:
  host: '192.168.124.51'
  port: '3306'
  user: 'root'
  password: 'jiushi'
  db: 'mxshop_user_srv'

name: 'user_srv'

consul:
  host: '192.168.124.51'
  port: '8500'
//user_srv/config_pro.yaml
mysql:
  host: '192.168.124.51'
  port: '3306'
  user: 'root'
  password: 'jiushi'
  db: 'mxshop_user_srv'

name: 'user_srv'

consul:
  host: '192.168.124.51'
  port: '8500'
  • user_srv/main.go
    • ①. Registration health check
    • ②. Registration service
package main

import (
	"flag"
	"fmt"
	"github.com/hashicorp/consul/api"
	"go.uber.org/zap"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"nd/user_srv/global"
	"nd/user_srv/handler"
	"nd/user_srv/initialize"
	"nd/user_srv/proto"
	"net"

	"google.golang.org/grpc"
)

func main() {
    
    
	IP := flag.String("ip", "0.0.0.0", "ip地址")
	Port := flag.Int("port", 50051, "端口号")

	//初始化
	initialize.InitLogger()
	initialize.InitConfig()
	initialize.InitDB()
	zap.S().Info(global.ServerConfig)

	flag.Parse()
	zap.S().Info("ip: ", *IP)
	zap.S().Info("port: ", *Port)

	server := grpc.NewServer()
	proto.RegisterUserServer(server, &handler.UserServer{
    
    })
	lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", *IP, *Port))
	if err != nil {
    
    
		panic("failed to listen:" + err.Error())
	}

	//注册服务健康检查
	grpc_health_v1.RegisterHealthServer(server, health.NewServer())

	//服务注册
	cfg := api.DefaultConfig()
	cfg.Address = fmt.Sprintf("%s:%d", global.ServerConfig.ConsulInfo.Host,
		global.ServerConfig.ConsulInfo.Port)

	client, err := api.NewClient(cfg)
	if err != nil {
    
    
		panic(err)
	}
	//生成对应的检查对象
	check := &api.AgentServiceCheck{
    
    
		GRPC:                           fmt.Sprintf("192.168.124.9:%d", *Port),
		Timeout:                        "5s",
		Interval:                       "5s",
		DeregisterCriticalServiceAfter: "15s",
	}

	//生成注册对象
	registration := new(api.AgentServiceRegistration)
	registration.Name = global.ServerConfig.Name
	registration.ID = global.ServerConfig.Name
	registration.Port = *Port
	registration.Tags = []string{
    
    "imooc", "bobby", "user", "srv"}
	registration.Address = "192.168.124.9"
	registration.Check = check

	err = client.Agent().ServiceRegister(registration)
	if err != nil {
    
    
		panic(err)
	}

	err = server.Serve(lis)
	if err != nil {
    
    
		panic("failed to start grpc:" + err.Error())
	}
}

insert image description here


Seven, gin integrated consul

The user_web layer needs to complete both service discovery and service registration

1 - UserSrvClient optimization

  • UserSrvClient optimization : Each interface needs UserSrvClient, and every time it is reacquired, it needs tcp three-way handshake, which is optimized to uniformly initialize the global UserSrvClient; of course, there is still a problem here, that is, multiple connections use the same UserSrvClient, this Subsequent re-optimization
  • user_web/global/global.go : add global UserSrvClient object
package global

import (
	ut "github.com/go-playground/universal-translator"

	"web_api/user_web/config"
	"web_api/user_web/proto"
)

var (
	Trans         ut.Translator
	ServerConfig  *config.ServerConfig = &config.ServerConfig{
    
    }
	UserSrvClient proto.UserClient
)

  • user_web/initialize/init_srv_conn.go : Add initialization business logic
package initialize

import (
	"fmt"
	"github.com/hashicorp/consul/api"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"web_api/user_web/global"
	"web_api/user_web/proto"
)

func InitSrvConn() {
    
    
	cfg := api.DefaultConfig()
	consulInfo := global.ServerConfig.ConsulInfo
	cfg.Address = fmt.Sprintf("%s:%d", consulInfo.Host, consulInfo.Port)

	userSrvHost := ""
	userSrvPort := 0

	client, err := api.NewClient(cfg)
	if err != nil {
    
    
		panic(err)
	}

	data, err := client.Agent().ServicesWithFilter(fmt.Sprintf("Service == \"%s\"", global.ServerConfig.UserSrvInfo.Name))
	if err != nil {
    
    
		panic(err)
	}

	// 只要获取一个就可以了
	for _, value := range data {
    
    
		userSrvHost = value.Address
		userSrvPort = value.Port
		break
	}

	if userSrvHost == "" {
    
    
		zap.S().Fatal("[InitSrvConn] 连接 【用户服务失败】")
		return
	}

	//拨号连接用户grpc服务器
	userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", userSrvHost, userSrvPort),
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
    
    
		zap.S().Errorw("[GetUserList] 连接 【用户服务失败】", "msg", err.Error())
	}
	// 1. 后续用户服务下线了如何处理  2. 该端口了 3. 改ip了
	// 已经事先建立好了链接,这样后续就不用再进行tcp的三次握手了
	// 一个连接多个groutine公用,性能问题 - 连接池
	userClient := proto.NewUserClient(userConn)
	global.UserSrvClient = userClient
}

  • user_web/main.go : Add connection to initialize srv
package main

import (
	"fmt"
	"web_api/user_web/global"
	"web_api/user_web/initialize"

	"github.com/gin-gonic/gin/binding"
	ut "github.com/go-playground/universal-translator"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"

	myvalidator "web_api/user_web/validator"
)

func main() {
    
    
	//1. 初始化logger
	initialize.InitLogger()
	//2. 初始化配置文件
	initialize.InitConfig()
	//3. 初始化routers
	Router := initialize.Routers()
	//4. 初始化翻译
	if err := initialize.InitTrans("zh"); err != nil {
    
    
		panic(err)
	}

	//5. 初始化srv的连接
	initialize.InitSrvConn()

	//注册验证器
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
    
    
		_ = v.RegisterValidation("mobile", myvalidator.ValidateMobile)
		_ = v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error {
    
    
			return ut.Add("mobile", "{0} 非法的手机号码!", true) // see universal-translator for details
		}, func(ut ut.Translator, fe validator.FieldError) string {
    
    
			t, _ := ut.T("mobile", fe.Field())
			return t
		})
	}

	/*
		1. S()可以获取一个全局的sugar,可以让我们自己设置一个全局的logger
		2. 日志是分级别的,debug, info , warn, error, fetal
			debug最低,fetal最高,如果配置成info,所有比info低的都不会输出
			NewProduction默认日志级别为info
			NewDevelopment默认日志级别为debug
		3. S函数和L函数很有用, 提供了一个全局的安全访问logger的途径
	*/
	zap.S().Debugf("启动服务器, 端口: %d", global.ServerConfig.Port)

	if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {
    
    
		zap.S().Panic("启动失败:", err.Error())
	}
}

2 - gin integrated consul

  • yaml configuration : add user_srv name, consul host and ip
//user_web/config_debug.yaml
name: 'user-web'
port: '8081'
user_srv:
  host: '127.0.0.1'
  port: '50051'
  name: 'user_srv'
jwt:
  key: 'VYLDYq3&hGWjWqF$K1ih'
sms:
  key: ''
  secrect: ''
  expire: 300
redis:
  host: '192.168.124.51'
  port: '6379'
consul:
  host: '192.168.124.51'
  port: '8500'

//user_web/config_pro.yaml
name: 'user-web'
port: '8081'
user_srv:
  host: '127.0.0.1'
  port: '50051'
  name: 'user_srv'
jwt:
  key: 'VYLDYq3&hGWjWqF$K1ih'
sms:
  key: ''
  secrect: ''
  expire: 300
redis:
  host: '192.168.124.51'
  port: '6379'
consul:
  host: '192.168.124.51'
  port: '8500'

  • user_web/api/api_user.go : Delete the operation of initializing UserSrvClient, and replace the corresponding UserSrvClient with global.UserSrvClient
package api

import (
	"context"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator"
	"github.com/go-redis/redis"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"web_api/user_web/forms"
	"web_api/user_web/global"
	"web_api/user_web/global/response"
	"web_api/user_web/middlewares"
	"web_api/user_web/models"
	"web_api/user_web/proto"
)

func HandleGrpcErrorToHttp(err error, c *gin.Context) {
    
    
	//将grpc的code转换成http的状态码
	if err != nil {
    
    
		if e, ok := status.FromError(err); ok {
    
    
			switch e.Code() {
    
    
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{
    
    
					"msg": e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError, gin.H{
    
    
					"msg:": "内部错误",
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest, gin.H{
    
    
					"msg": "参数错误",
				})
			case codes.Unavailable:
				c.JSON(http.StatusInternalServerError, gin.H{
    
    
					"msg": "用户服务不可用",
				})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{
    
    
					"msg": e.Code(),
				})
			}
			return
		}
	}
}

func HandleValidatorError(c *gin.Context, err error) {
    
    
	errs, ok := err.(validator.ValidationErrors)
	if !ok {
    
    
		c.JSON(http.StatusOK, gin.H{
    
    
			"msg": err.Error(),
		})
	}
	c.JSON(http.StatusBadRequest, gin.H{
    
    
		"error": removeTopStruct(errs.Translate(global.Trans)),
	})
}

func removeTopStruct(fields map[string]string) map[string]string {
    
    
	rsp := map[string]string{
    
    }
	for field, err := range fields {
    
    
		rsp[field[strings.Index(field, ".")+1:]] = err
	}
	return rsp
}

func GetUserList(ctx *gin.Context) {
    
    
	//拨号连接用户grpc服务器 跨域的问题 - 后端解决 也可以前端来解决
	//claims, _ := ctx.Get("claims")
	//currentUser := claims.(*models.CustomClaims)
	//zap.S().Infof("访问用户: %d", currentUser.ID)

	pn := ctx.DefaultQuery("pn", "0")
	pnInt, _ := strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("psize", "10")
	pSizeInt, _ := strconv.Atoi(pSize)

	rsp, err := global.UserSrvClient.GetUserList(context.Background(), &proto.PageInfo{
    
    
		Pn:    uint32(pnInt),
		PSize: uint32(pSizeInt),
	})
	if err != nil {
    
    
		zap.S().Errorw("[GetUserList] 查询 【用户列表】 失败")
		HandleGrpcErrorToHttp(err, ctx)
		return
	}

	result := make([]interface{
    
    }, 0)
	for _, value := range rsp.Data {
    
    
		user := response.UserResponse{
    
    
			Id:       value.Id,
			NickName: value.NickName,
			//Birthday: time.Time(time.Unix(int64(value.BirthDay), 0)).Format("2006-01-02"),
			Birthday: response.JsonTime(time.Unix(int64(value.BirthDay), 0)),
			Gender:   value.Gender,
			Mobile:   value.Mobile,
		}
		result = append(result, user)
	}

	ctx.JSON(http.StatusOK, result)
}

func PassWordLogin(c *gin.Context) {
    
    
	//表单验证
	passwordLoginForm := forms.PassWordLoginForm{
    
    }
	if err := c.ShouldBind(&passwordLoginForm); err != nil {
    
    
		HandleValidatorError(c, err)
		return
	}

	if store.Verify(passwordLoginForm.CaptchaId, passwordLoginForm.Captcha, false) {
    
    
		c.JSON(http.StatusBadRequest, gin.H{
    
    
			"captcha": "验证码错误",
		})
		return
	}

	//登录逻辑
	if rsp, err := global.UserSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequest{
    
    
		Mobile: passwordLoginForm.Mobile,
	}); err != nil {
    
    
		if e, ok := status.FromError(err); ok {
    
    
			switch e.Code() {
    
    
			case codes.NotFound:
				c.JSON(http.StatusBadRequest, map[string]string{
    
    
					"mobile": "用户不存在",
				})
			default:
				c.JSON(http.StatusInternalServerError, map[string]string{
    
    
					"mobile": "登录失败",
				})
			}
			return
		}
	} else {
    
    
		//只是查询到用户了而已,并没有检查密码
		if passRsp, pasErr := global.UserSrvClient.CheckPassWord(context.Background(), &proto.PasswordCheckInfo{
    
    
			Password:          passwordLoginForm.PassWord,
			EncryptedPassword: rsp.PassWord,
		}); pasErr != nil {
    
    
			c.JSON(http.StatusInternalServerError, map[string]string{
    
    
				"password": "登录失败",
			})
		} else {
    
    
			if passRsp.Success {
    
    
				//生成token
				j := middlewares.NewJWT()
				claims := models.CustomClaims{
    
    
					ID:          uint(rsp.Id),
					NickName:    rsp.NickName,
					AuthorityId: uint(rsp.Role),
					StandardClaims: jwt.StandardClaims{
    
    
						NotBefore: time.Now().Unix(),               //签名的生效时间
						ExpiresAt: time.Now().Unix() + 60*60*24*30, //30天过期
						Issuer:    "imooc",
					},
				}
				token, err := j.CreateToken(claims)
				if err != nil {
    
    
					c.JSON(http.StatusInternalServerError, gin.H{
    
    
						"msg": "生成token失败",
					})
					return
				}

				c.JSON(http.StatusOK, gin.H{
    
    
					"id":         rsp.Id,
					"nick_name":  rsp.NickName,
					"token":      token,
					"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
				})
			} else {
    
    
				c.JSON(http.StatusBadRequest, map[string]string{
    
    
					"msg": "登录失败",
				})
			}
		}
	}
}

func Register(c *gin.Context) {
    
    
	//用户注册
	registerForm := forms.RegisterForm{
    
    }
	if err := c.ShouldBind(&registerForm); err != nil {
    
    
		HandleValidatorError(c, err)
		return
	}

	//验证码
	rdb := redis.NewClient(&redis.Options{
    
    
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	value, err := rdb.Get(registerForm.Mobile).Result()
	if err == redis.Nil {
    
    
		c.JSON(http.StatusBadRequest, gin.H{
    
    
			"code": "验证码错误",
		})
		return
	} else {
    
    
		if value != registerForm.Code {
    
    
			c.JSON(http.StatusBadRequest, gin.H{
    
    
				"code": "验证码错误",
			})
			return
		}
	}

	user, err := global.UserSrvClient.CreateUser(context.Background(), &proto.CreateUserInfo{
    
    
		NickName: registerForm.Mobile,
		PassWord: registerForm.PassWord,
		Mobile:   registerForm.Mobile,
	})

	if err != nil {
    
    
		zap.S().Errorf("[Register] 查询 【新建用户失败】失败: %s", err.Error())
		HandleGrpcErrorToHttp(err, c)
		return
	}

	j := middlewares.NewJWT()
	claims := models.CustomClaims{
    
    
		ID:          uint(user.Id),
		NickName:    user.NickName,
		AuthorityId: uint(user.Role),
		StandardClaims: jwt.StandardClaims{
    
    
			NotBefore: time.Now().Unix(),               //签名的生效时间
			ExpiresAt: time.Now().Unix() + 60*60*24*30, //30天过期
			Issuer:    "imooc",
		},
	}
	token, err := j.CreateToken(claims)
	if err != nil {
    
    
		c.JSON(http.StatusInternalServerError, gin.H{
    
    
			"msg": "生成token失败",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
    
    
		"id":         user.Id,
		"nick_name":  user.NickName,
		"token":      token,
		"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
	})
}

insert image description here


8. Complete source code

mxshop_srvsV6.0.rar

Guess you like

Origin blog.csdn.net/qq23001186/article/details/126025480