Files
service-gateway/internal/handler/http_handler/login.go

140 lines
3.7 KiB
Go

package http_handler
import (
"context"
"fmt"
"git.hlsq.asia/mmorpg/service-common/db/redis"
"git.hlsq.asia/mmorpg/service-common/log"
"git.hlsq.asia/mmorpg/service-common/net/grpc/service"
"git.hlsq.asia/mmorpg/service-common/net/http/http_resp"
"git.hlsq.asia/mmorpg/service-common/proto/rs/grpc_pb"
"git.hlsq.asia/mmorpg/service-common/utils"
"git.hlsq.asia/mmorpg/service-gateway/config"
"git.hlsq.asia/mmorpg/service-gateway/internal/global"
"github.com/gin-gonic/gin"
"time"
)
// 这个模块处理用户登录
type LoginReq struct {
Phone string `json:"phone"` // 手机号
Code string `json:"code"` // 验证码
WxMiniCode string `json:"wxMiniCode"` // 微信小程序登录
}
type LoginResp struct {
USN string `json:"usn"`
Name string `json:"name"`
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
}
func Login(c *gin.Context) {
req := &LoginReq{}
if err := c.ShouldBindJSON(req); err != nil {
http_resp.JsonBadRequest(c)
return
}
client, err := service.UserNewClientLB()
if err != nil {
log.Errorf("Login UserNewClientLB error: %v", err)
http_resp.JsonOK(c, http_resp.Error(http_resp.Failed))
return
}
usn, name := "", ""
if req.Phone != "" {
// TODO 校验验证码
login, err := client.PhoneLogin(c, &grpc_pb.PhoneLoginReq{
Phone: req.Phone,
Code: req.Code,
})
if err != nil {
log.Errorf("Login PhoneLogin error: %v", err)
http_resp.JsonOK(c, http_resp.Error(http_resp.Failed))
return
}
usn, name = login.USN, login.Name
} else if req.WxMiniCode != "" {
login, err := client.WxMiniLogin(c, &grpc_pb.WxMiniLoginReq{
Code: req.WxMiniCode,
})
if err != nil {
log.Errorf("Login WxMiniLogin error: %v", err)
http_resp.JsonOK(c, http_resp.Error(http_resp.Failed))
return
}
usn, name = login.USN, login.Name
} else {
http_resp.JsonBadRequest(c)
return
}
at, rt, err := genToken(c, usn)
http_resp.JsonOK(c, http_resp.Success(&LoginResp{
USN: usn,
Name: name,
AccessToken: at,
RefreshToken: rt,
}))
}
type RefreshTokenReq struct {
RefreshToken string `json:"refreshToken" binding:"required,min=1"`
}
type RefreshTokenResp struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
}
func RefreshToken(c *gin.Context) {
req := &RefreshTokenReq{}
if err := c.ShouldBindJSON(req); err != nil {
http_resp.JsonBadRequest(c)
return
}
claims, err := utils.ParseToken(req.RefreshToken, config.Get().Auth.Secret)
if err != nil {
http_resp.JsonOK(c, http_resp.Error(http_resp.TokenInvalid))
return
}
if redis.GetClient().Get(c, fmt.Sprintf(global.KeyGatewayRefreshToken, claims.USN)).Val() != req.RefreshToken {
http_resp.JsonOK(c, http_resp.Error(http_resp.TokenInvalid))
return
}
at, rt, err := genToken(c, claims.USN)
if err != nil {
log.Errorf("RefreshToken genToken error: %v, usn: %v", err, claims.USN)
http_resp.JsonOK(c, http_resp.Error(http_resp.Failed))
return
}
http_resp.JsonOK(c, http_resp.Success(&RefreshTokenResp{
AccessToken: at,
RefreshToken: rt,
}))
}
func genToken(ctx context.Context, usn string) (string, string, error) {
at, err := genTokenOne(ctx, global.KeyGatewayAccessToken, usn, 2*time.Hour)
if err != nil {
return "", "", err
}
rt, err := genTokenOne(ctx, global.KeyGatewayRefreshToken, usn, 3*24*time.Hour)
if err != nil {
return "", "", err
}
return at, rt, nil
}
func genTokenOne(ctx context.Context, key string, usn string, ttl time.Duration) (string, error) {
token, err := utils.GenToken(usn, config.Get().Auth.Secret, time.Duration(config.Get().Auth.Expire)*time.Second)
if err != nil {
return "", err
}
redis.GetClient().Set(ctx, fmt.Sprintf(key, usn), token, ttl)
return token, err
}