package controller import ( "crypto/md5" "encoding/base64" "encoding/hex" "encoding/json" providerApiEntity "flswld.com/annie-user-api/entity" "flswld.com/common/utils/endec" "flswld.com/common/utils/random" "flswld.com/logger" "gate-hk4e/entity/api" "gate-hk4e/entity/db" "github.com/gin-gonic/gin" "net/http" "regexp" "strconv" "strings" ) func (c *Controller) getMD5(src string) string { ctx := md5.New() ctx.Write([]byte(src)) return hex.EncodeToString(ctx.Sum(nil)) } func (c *Controller) apiLogin(context *gin.Context) { requestData := new(api.LoginAccountRequestJson) err := context.ShouldBindJSON(requestData) if err != nil { logger.LOG.Error("parse LoginAccountRequestJson error: %v", err) return } encPwdData, err := base64.StdEncoding.DecodeString(requestData.Password) if err != nil { logger.LOG.Error("decode password enc data error: %v", err) return } pwdPrivKey, err := endec.RsaParsePrivKey(c.pwdRsaKey) if err != nil { logger.LOG.Error("parse rsa key error: %v", err) return } pwdDecData, err := endec.RsaDecrypt(encPwdData, pwdPrivKey) useAtAtMode := false if err != nil { logger.LOG.Debug("rsa dec error: %v", err) logger.LOG.Debug("password rsa dec fail, fallback to @@ mode") useAtAtMode = true } else { logger.LOG.Debug("password dec: %v", string(pwdDecData)) useAtAtMode = false } responseData := api.NewLoginResult() var username string var password string if useAtAtMode { // 账号格式检查 用户名6-20字符 密码8-20字符 用户名和密码公用account字段 第一次出现的@@视为分割标识 username@@password if len(requestData.Account) > 20+20+2 { responseData.Retcode = -201 responseData.Message = "用户名或密码长度超限" context.JSON(http.StatusOK, responseData) return } if !strings.Contains(requestData.Account, "@@") { responseData.Retcode = -201 responseData.Message = "用户名同密码均填写到用户名输入框,填写格式为:用户名@@密码,密码输入框填写任意字符均可" context.JSON(http.StatusOK, responseData) return } atIndex := strings.Index(requestData.Account, "@@") username = requestData.Account[:atIndex] password = requestData.Account[atIndex+2:] } else { username = requestData.Account password = string(pwdDecData) } if len(username) < 6 || len(username) > 20 { responseData.Retcode = -201 responseData.Message = "用户名为6-20位字符" context.JSON(http.StatusOK, responseData) return } if len(password) < 8 || len(password) > 20 { responseData.Retcode = -201 responseData.Message = "密码为8-20位字符" context.JSON(http.StatusOK, responseData) return } ok, err := regexp.MatchString("^[a-zA-Z0-9]{6,20}$", username) if err != nil || !ok { responseData.Retcode = -201 responseData.Message = "用户名只能包含大小写字母和数字" context.JSON(http.StatusOK, responseData) return } userList := make([]providerApiEntity.User, 0) ok = c.rpcUserConsumer.CallFunction("RpcService", "RpcQueryUser", &providerApiEntity.User{Username: username}, &userList) if !ok { responseData.Retcode = -201 responseData.Message = "服务器内部错误:-1" context.JSON(http.StatusOK, responseData) return } if len(userList) != 1 { responseData.Retcode = -201 responseData.Message = "用户名不存在" context.JSON(http.StatusOK, responseData) return } user := userList[0] if c.getMD5(password) != user.Password { responseData.Retcode = -201 responseData.Message = "用户名或密码错误" context.JSON(http.StatusOK, responseData) return } // 登录成功 account, err := c.dao.QueryAccountByField("username", username) if err != nil { logger.LOG.Error("query account from db error: %v", err) return } if account == nil { // 注册一个原神account playerID, err := c.dao.GetNextYuanShenUid() if err != nil { responseData.Retcode = -201 responseData.Message = "服务器内部错误:-2" context.JSON(http.StatusOK, responseData) return } regAccount := &db.Account{ Uid: user.Uid, Username: username, PlayerID: playerID, Token: base64.StdEncoding.EncodeToString(random.GetRandomByte(24)), ComboToken: "", } _, err = c.dao.InsertAccount(regAccount) if err != nil { responseData.Retcode = -201 responseData.Message = "服务器内部错误:-3" context.JSON(http.StatusOK, responseData) return } responseData.Message = "OK" responseData.Data.Account.Uid = strconv.FormatInt(int64(regAccount.Uid), 10) responseData.Data.Account.Token = regAccount.Token responseData.Data.Account.Email = regAccount.Username } else { // 生产新的token account.Token = base64.StdEncoding.EncodeToString(random.GetRandomByte(24)) _, err := c.dao.UpdateAccountFieldByFieldName("uid", account.Uid, "token", account.Token) if err != nil { responseData.Retcode = -201 responseData.Message = "服务器内部错误:-4" context.JSON(http.StatusOK, responseData) return } responseData.Message = "OK" responseData.Data.Account.Uid = strconv.FormatInt(int64(account.Uid), 10) responseData.Data.Account.Token = account.Token responseData.Data.Account.Email = account.Username } context.JSON(http.StatusOK, responseData) } func (c *Controller) apiVerify(context *gin.Context) { requestData := new(api.LoginTokenRequest) err := context.ShouldBindJSON(requestData) if err != nil { logger.LOG.Error("parse LoginTokenRequest error: %v", err) return } uid, err := strconv.ParseInt(requestData.Uid, 10, 64) if err != nil { logger.LOG.Error("parse uid error: %v", err) return } account, err := c.dao.QueryAccountByField("uid", uid) if err != nil { logger.LOG.Error("query account from db error: %v", err) return } responseData := api.NewLoginResult() if account == nil || account.Token != requestData.Token { responseData.Retcode = -111 responseData.Message = "账号本地缓存信息错误" context.JSON(http.StatusOK, responseData) return } responseData.Message = "OK" responseData.Data.Account.Uid = requestData.Uid responseData.Data.Account.Token = requestData.Token responseData.Data.Account.Email = account.Username context.JSON(http.StatusOK, responseData) } func (c *Controller) v2Login(context *gin.Context) { requestData := new(api.ComboTokenReq) err := context.ShouldBindJSON(requestData) if err != nil { logger.LOG.Error("parse ComboTokenReq error: %v", err) return } data := requestData.Data if len(data) == 0 { logger.LOG.Error("requestData.Data len == 0") return } loginData := new(api.LoginTokenData) err = json.Unmarshal([]byte(data), loginData) if err != nil { logger.LOG.Error("Unmarshal LoginTokenData error: %v", err) return } uid, err := strconv.ParseInt(loginData.Uid, 10, 64) if err != nil { logger.LOG.Error("ParseInt uid error: %v", err) return } responseData := api.NewComboTokenRes() account, err := c.dao.QueryAccountByField("uid", uid) if account == nil || account.Token != loginData.Token { responseData.Retcode = -201 responseData.Message = "token错误" context.JSON(http.StatusOK, responseData) return } // 生成新的comboToken account.ComboToken = random.GetRandomByteHexStr(20) _, err = c.dao.UpdateAccountFieldByFieldName("uid", account.Uid, "comboToken", account.ComboToken) if err != nil { responseData.Retcode = -201 responseData.Message = "服务器内部错误:-1" context.JSON(http.StatusOK, responseData) return } responseData.Message = "OK" responseData.Data.OpenID = loginData.Uid responseData.Data.ComboID = "0" responseData.Data.ComboToken = account.ComboToken context.JSON(http.StatusOK, responseData) }