golang 用戶管理系統


最近開始接觸golang,寫了一個簡單的用戶管理系統練手:

  1. webserver 基於gin開發
  2. tcpserver 基於grpc
  3. redis / db

支持登入、登出;上傳頭像、修改昵稱;盡量編寫了足夠的單元測試,並且代碼都通過golint和go vet的檢查。

項目地址在這:Git地址

 

代碼結構說明如下:

|-- conf // yaml格式的http server, tcp server配置;及配置解析代碼 |-- doc // 包括設計文檔、測試文檔 |-- gpool // grpc 連接池 |-- code // 定義的錯誤碼和提示消息 |-- utils // 公共函數 |-- httpserver // http server代碼 | |-- static // web相關代碼 html/css/js | |-- upload/images // 頭像存儲地址 | |-- handler.go // 請求處理handler | |-- testhandler.go // 供壓測和測試用的接口 | `-- main.go // 入口文件 |-- proto // grpc 協議文件 |-- rpcclient // grpc 客戶端代碼 |-- tcpserver |-- cache.go // redis |-- db.go // db 操作 |-- user_dao.go // redis/db 操作交互 |-- userserver.go // grpc server `-- main.go // 入口文件

 

主要功能點

  • 認證

用戶登錄時,會生成唯一的sessionid作為token,作為key緩存到redis中。其對應的value是全部的用戶信息。這樣做除了加快查詢外,后續的其他接口的操作都需要用戶傳遞用戶名過來(假設用戶名是全局唯一的),鑒權的時候不僅校驗token,同時也比對用戶名,防止token沖突的情況發生。用戶登錄的時候密碼都以md5加密傳輸過來,然后在db中存儲的用戶密碼是采用“密碼加鹽”的方式。

當然,這樣沒有辦法避免中間人攻擊。更可靠的是采用https傳輸。同時在登錄的時候,前后端通過協商的方式生成秘鑰對,進行加解密。

  • 日志

日志采用beego/logs,開始的時候考慮用open tracing與grpc結合起來做調用鏈追蹤。后來為了簡化起見,只是在請求一到達webserver的時候就生成唯一的請求ID,同時約定日志的第一個字段就是該ID。

然后通過context的metadata傳遞到grpc server。后者取出這個ID,以同樣的方式記錄日志。做到單個請求可追溯,同時又不破壞正常請求的傳輸。

  • MySQL

mysql采用gorm,由於考慮到數據量大的情況,可能需要做分表。因此在gorm db操作的時候要注意:

// User gorm user object type User struct { ID int32 `gorm:"type:int(11);primary key"` Username string `gorm:"type:varchar(64);unique;not null"` Nickname string `gorm:"type:varchar(128)"` Passwd string `gorm:"type:varchar(32);not null"` Skey string `gorm:"type:varchar(16);not null"` Headurl string `gorm:"type:varchar(128);unique;not null"` Uptime int64 `gorm:"type:datetime"` } // TableName gorm use this to get tablename // NOTE : it only works int where caulse func (u User) TableName() string { var value int for _, c := range []rune(u.Username) { value = value + int(c) } return fmt.Sprintf("userinfo_tab_%d", value % 20) } 

在查詢的時候也可以指定tab名字:

db.Table(user.TableName()).Where(&User{Username:username}).First(&quser)

配置文件采用yaml的方式,redis則使用go-redis

 

  • grpc連接池

grpc雖然支持http2.0多路復用,但是並發高的時候,還是需要連接池來做連接復用。

之前打算用sync.Pool來做連接池,后來有看到說sync.Pool主要是作為對象池,用來做連接池不太合適。於是邊用chan 封裝了一個簡單的連接池。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM