云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第4篇...
游客登录鉴权之业务代码实战
系列文章
- 从0到1使用Golang开发生产级麻将游戏服务器—第1篇
- 从0到1使用Golang开发生产级麻将游戏服务器—第2篇
- 从0到1使用Golang开发生产级麻将游戏服务器—第3篇
介绍
这将是一个完整的,完全践行 DevOps/GitOps 与 Kubernetes 上云流程的 Golang 游戏服务器开发的系列教程。
这个系列教程是对开源项目 Nanoserver 的完整拆解,旨在帮助大家快速上手 Golang(游戏)服务器后端开发。通过实践去理解 Golang 开发的精髓 —— Share memory by communication(通过通信共享内存)。
同时这个项目可能还会涉及到 Linux 性能调优(BPF 相关的工具)和系统保障(SRE)的相关的工作。
Step-By-Step 开发 Mahjong Server
单体架构理解Mahjong Server业务 ->Nano Distributed Game Server(分布式)+微服务改造。- Demo:go-mahjong-server
VSCode REST Client 插件
如果你是用 VSCode 作为 IDE,这个插件不错:
游客登录业务
业务分析
从0到1使用Golang开发生产级麻将游戏服务器—第3篇
业务 E-R 图
API:查询游客登录是否启用
REST Client 测试 API
Request:
POST http://192.168.31.125:12307/v1/user/login/query HTTP/1.1
content-type: application/json{"channelId": "konglai","appId": "konglai"
} Response:
HTTP/1.1 200 OK
Access-Control-Allow-Headers: Origin, Content-Type, Authorization
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Sun, 07 Feb 2021 15:00:16 GMT
Content-Length: 24
Connection: close{"code": 0,"guest": true
}
业务逻辑分析
- 比较简单,就是根据服务器
configs/config.toml文件的配置,进行验证:
...
[login]
guest = true
lists = ["test", "konglai"]
... API:游客登录
REST Client 测试 API
Request:
POST http://127.0.0.1:12307/v1/user/login/guest HTTP/1.1
content-type: application/json{"channelId": "konglai","appId": "konglai","imei": "c0a4ce912c48a3d0b17b59e6b97f1dca"
} Response:
{"code": 0,"name": "G1","uid": 1,"headUrl": "http://wx.qlogo.cn/mmopen/s962LEwpLxhQSOnarDnceXjSxVGaibMRsvRM4EIWic0U6fQdkpqz4Vr8XS8D81QKfyYuwjwm2M2ibsFY8mia8ic51ww/0","fangka": 10,"sex": 1,"ip": "192.168.31.125","port": 33251,"playerIp": "192.168.31.125","config": {"version": "1.9.3","android": "https://fir.im/tand","ios": "https://fir.im/tios","heartbeat": 30,"forceUpdate": true,"title": "血战到底","desc": "纯正四川玩法,快捷便利的掌上血战,轻松组局,随时随地尽情游戏","daili1": "kefuweixin01","daili2": "kefuweixin01","kefu1": "kefuweixin01","appId": "xxx","appKey": "xxx"},"messages": ["系统消息:健康游戏,禁止赌博", "欢迎进入游戏"],"clubList": [],"debug": 0
} 业务逻辑分析
DB Model
db/model/struct.go
type User struct {Id int64Algo string `xorm:"not null VARCHAR(16) default"`Hash string `xorm:"not null VARCHAR(64) default"`Salt string `xorm:"not null VARCHAR(64) default"`Role int `xorm:"not null TINYINT(3) default 1"`Status int `xorm:"not null TINYINT(3) default 1"`IsOnline int `xorm:"not null TINYINT(1) default 1"`LastLoginAt int64 `xorm:"not null index BIGINT(11) default"`PrivKey string `xorm:"not null VARCHAR(512) default"`PubKey string `xorm:"not null VARCHAR(128) default"`Coin int64 `xorm:"not null BIGINT(20) default 0"`RegisterAt int64 `xorm:"not null index BIGINT(20) default 0"`FirstRechargeAt int64 `xorm:"not null index BIGINT(20) default 0"`Debug int `xorm:"not null index TINYINT(1) default 0"`
} | 用户表 | 描述 |
|---|---|
| Id | 自增ID |
| Algo | 加密算法 |
| Hash | 加密hash |
| Salt | 加密撒盐 |
| Role | 账号类型(RoleTypeAdmin=1 管理员账号,RoleTypeThird=2 三方平台账号) |
| Status | 账号状态(StatusNormal=1 正常,StatusDeleted=2 删除,StatusFreezed=3 冻结,StatusBound=4 绑定) |
| IsOnline | 是否在线(UserOffline=1 离线,UserOnline=2 在线) |
| LastLoginAt | 最后登录时间 |
| PrivKey | 账号证书私钥 |
| PubKey | 账号证书公钥 |
| Coin | 房卡数量 |
| RegisterAt | 注册时间 |
| FirstRechargeAt | 首充时间 |
| Debug | 用户信息调试 |
type Register struct {Id int64Uid int64 `xorm:"not null index BIGINT(20) default"`Remote string `xorm:"not null VARCHAR(40) default"`Ip string `xorm:"not null VARCHAR(40) default"`Imei string `xorm:"not null VARCHAR(128) default"`Os string `xorm:"not null VARCHAR(20) default"`Model string `xorm:"not null VARCHAR(20) default"`AppId string `xorm:"not null index VARCHAR(32) default"`ChannelId string `xorm:"not null index VARCHAR(32) default"`RegisterAt int64 `xorm:"not null index BIGINT(11) default"`RegisterType int `xorm:"not null index TINYINT(8) default"`
} | 用户注册记录表 | 描述 |
|---|---|
| Id | 自增ID |
| Uid | 用户ID |
| Remote | 外网IP |
| Ip | 内网IP |
| Model | 硬件型号 |
| Imei | 设备的imei号 |
| Os | os版本号 |
| AppId | 应用id |
| ChannelId | 渠道id |
| RegisterAt | 注册时间 |
| RegisterType | 注册类型(RegTypeThird=5 三方平台添加账号) |
type Login struct {Id int64Uid int64 `xorm:"not null index BIGINT(20) default"`Remote string `xorm:"not null VARCHAR(40) default"`Ip string `xorm:"not null VARCHAR(40) default"`Model string `xorm:"not null VARCHAR(64) default"`Imei string `xorm:"not null VARCHAR(32) default"`Os string `xorm:"not null VARCHAR(64) default"`AppId string `xorm:"not null VARCHAR(64) default"`ChannelId string `xorm:"not null VARCHAR(32) default"`LoginAt int64 `xorm:"not null BIGINT(11) default"`LogoutAt int64 `xorm:"not null BIGINT(11) default"`
} | 用户登录记录表 | 描述 |
|---|---|
| Id | 自增ID |
| Uid | 用户ID |
| Remote | 外网IP |
| Ip | 内网IP |
| Model | 硬件型号 |
| Imei | 设备的imei号 |
| Os | os版本号 |
| AppId | 应用id |
| ChannelId | 渠道id |
| LoginAt | 登录时间 |
| LogoutAt | 注销时间 |
- 根据
AppID(用户来自于哪一个应用) 与Device.IMEI(设备的imei号),确定当前游客是否已经注册
user, err := db.QueryGuestUser(data.AppID, data.Device.IMEI) db.QueryGuestUser,会从 register 或 user 表中去查找用户是否存在。
相关 protocol 的定义:
protocol/login.go
type LoginRequest struct {AppID string `json:"appId"` //用户来自于哪一个应用ChannelID string `json:"channelId"` //用户来自于哪一个渠道IMEI string `json:"imei"`Device Device `json:"device"`
} protocol/common.go
type Device struct {IMEI string `json:"imei"` //设备的imei号OS string `json:"os"` //os版本号Model string `json:"model"` //硬件型号IP string `json:"ip"` //内网IPRemote string `json:"remote"` //外网IP
} - 如果没有注册,则生成一个新用户,并且注册一条用户记录
涉及到的相关 db 常量的定义:
db/const.go
const (StatusNormal = 1 //正常StatusDeleted = 2 //删除StatusFreezed = 3 //冻结StatusBound = 4 //绑定
)const (UserOffline = 1 //离线UserOnline = 2 //在线
)// Users表中role字段的取值
const (RoleTypeAdmin = 1 //管理员账号RoleTypeThird = 2 //三方平台账号
) 生成一个新用户:
const defaultCoin = 10 // 默认给的房卡数量是 10user = &model.User{Status: db.StatusNormal,IsOnline: db.UserOffline,Role: db.RoleTypeThird,Coin: defaultCoin,
}db.InsertUser(user) 注册一条用户记录
db.RegisterUserLog(user, data.Device, data.AppID, data.ChannelID, protocol.RegTypeThird) //注册记录 - 构造
login响应数据
相关 protocol 的定义:
protocol/login.go
type LoginResponse struct {Code int `json:"code"`Name string `json:"name"`Uid int64 `json:"uid"`HeadUrl string `json:"headUrl"`FangKa int64 `json:"fangka"`Sex int `json:"sex"` //[0]未知 [1]男 [2]女IP string `json:"ip"`Port int `json:"port"`PlayerIP string `json:"playerIp"`Config ClientConfig `json:"config"`Messages []string `json:"messages"`ClubList []ClubItem `json:"clubList"`Debug int `json:"debug"`
}type ClientConfig struct {Version string `json:"version"`Android string `json:"android"`IOS string `json:"ios"`Heartbeat int `json:"heartbeat"`ForceUpdate bool `json:"forceUpdate"`Title string `json:"title"` // 分享标题Desc string `json:"desc"` // 分享描述Daili1 string `json:"daili1"`Daili2 string `json:"daili2"`Kefu1 string `json:"kefu1"`AppId string `json:"appId"`AppKey string `json:"appKey"`
} protocol/club.go
type (ClubItem struct {Id int64 `json:"id"`Name string `json:"name"`Desc string `json:"desc"`Member int `json:"member"`MaxMember int `json:"maxMember"`}// ....
) - 插入登录记录,返回客户端所需数据
device := protocol.Device{IP: ip(r.RemoteAddr),Remote: r.RemoteAddr,}
db.InsertLoginLog(user.Id, device, data.AppID, data.ChannelID)return resp, nil - 一图胜千言,秒懂
关于游戏服务器登录与 Nano 游戏服务器通信相关代码实战,我们下篇再详细讨论。
我是为少
微信:uuhells123
公众号:黑客下午茶
加我微信(互相学习交流),关注公众号(获取更多学习资料~)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
