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