package account import ( "encoding/hex" "errors" "mtp20access/global" accountModel "mtp20access/model/account" "mtp20access/model/account/request" jwtRequest "mtp20access/model/common/request" "sync" "mtp20access/utils" "strconv" "go.uber.org/zap" ) var ( mtx sync.RWMutex curSessionID int = 90000 // 本服务SessionID从90000开始,以避免与旧登录服务重叠 ) // Login 用户登录 func Login(req request.LoginReq, addr string) (loginaccount *accountModel.Loginaccount, token string, expiresAt int64, err error) { // 分别尝试用LoginID、LoginCode和手机号码进行登录 loginaccount, err = getLoginAccount(req.UserName, req.Password) if err != nil { return } // 判断用户状态 if loginaccount.LOGINSTATUS == 2 { err = errors.New("账户已冻结") return } if loginaccount.LOGINSTATUS == 3 { err = errors.New("账户已注销") return } // 生成Token,并写入Redis if token, expiresAt, err = buildRedisLoginInfo(*loginaccount, addr, req.ClientType); err != nil { return } return } // getLoginAccount 分别尝试用LoginID、LoginCode和手机号码进行登录 func getLoginAccount(userName string, password string) (loginaccount *accountModel.Loginaccount, err error) { // LoginID if loginID, _ := strconv.Atoi(userName); loginID != 0 { loginaccount = &accountModel.Loginaccount{ LOGINID: int64(loginID), PASSWORD: password, } if has, _ := global.M2A_DB.Get(loginaccount); has { return } } // LoginCode loginaccount = &accountModel.Loginaccount{ LOGINCODE: userName, PASSWORD: password, } if has, _ := global.M2A_DB.Get(loginaccount); has { return } // 手机号码,需要AES加密 key, _ := hex.DecodeString(utils.AESSecretKey) if mobileEncrypted, _ := utils.AESEncrypt([]byte(userName), key); mobileEncrypted != nil { loginaccount = &accountModel.Loginaccount{ MOBILE: string(mobileEncrypted), PASSWORD: password, } if has, _ := global.M2A_DB.Get(loginaccount); has { return } } err = errors.New("错误的用户名或密码") return } // newSessionID 获取 func newSessionID() int { mtx.Lock() curSessionID += 1 mtx.Unlock() return curSessionID } // buildRedisLoginInfo 生成Token,并写入Redis func buildRedisLoginInfo(loginaccount accountModel.Loginaccount, addr string, group int) (token string, expiresAt int64, err error) { // 生成SessionID sessionID := newSessionID() // 生成本服务Token j := &utils.JWT{SigningKey: []byte(global.M2A_CONFIG.JWT.SigningKey)} // 唯一签名 claims := j.CreateClaims(jwtRequest.BaseClaims{ LoginID: int(loginaccount.LOGINID), SessionID: sessionID, }) token, err = j.CreateToken(claims) if err != nil { global.M2A_LOG.Error("生成本服token失败", zap.Error(err)) return } expiresAt = claims.RegisteredClaims.ExpiresAt.Unix() loginLogin := global.LoginRedis{ LoginID: strconv.Itoa(int(loginaccount.LOGINID)), UserID: strconv.Itoa(int(loginaccount.USERID)), SessionID: strconv.Itoa(sessionID), Token: token, Group: strconv.Itoa(group), Addr: addr, } loginMap, err := loginLogin.ToMap() // loginMap := map[string]interface{}{ // "LoginID": strconv.Itoa(int(loginaccount.LOGINID)), // "UserID": strconv.Itoa(int(loginaccount.USERID)), // "SessionID": strconv.Itoa(sessionID), // "Token": token, // "Group": strconv.Itoa(group), // "Addr": addr, // } if err != nil { global.M2A_LOG.Error("生成登录信息MAP失败", zap.Error(err)) return } if err = j.SetRedisLogin(int(loginaccount.LOGINID), group, loginMap); err != nil { global.M2A_LOG.Error("Token写入Redis失败", zap.Error(err)) return } // 生成旧登录服务Token // if err = j.SetOriRedisToken(int(loginaccount.LOGINID), group); err != nil { // // FIXME: 这里有类事务的回滚问题 // global.M2A_LOG.Error("生成旧登录服务Token失败", zap.Error(err)) // return // } return }