golang用户管理库
- 游客注册、用户名+密码注册、邮箱+验证码注册、手机号+验证注册、第三方注册
- 游客直接登录、用户名+密码直接登录、手机号+验证直接登录、第三方直接登录
- 按uid、邮箱、手机号、第三方uid查找用户
- 用户管理
- 多端登录
- 登录凭证(token)的验证
- 访问秘钥(accesskey)的验证和管理
- 验证码的生成和验证
- 多种模块的自定义
go get github.com/cheetah-fun-gs/gouser
import (
"github.com/cheetah-fun-gs/gouser"
)
gouser.New(name, secret, pool, db)
gouser.New(name, secret, pool, db, gouser.Config{})
func (mgr *UserMgr) RegisterAuth(authName string, v interface{}) (*User, error)
RegisterAuth 第三方认证注册
func (mgr *UserMgr) RegisterEmail(email, code string) (*User, error)
RegisterEmail 邮件用户注册
func (mgr *UserMgr) RegisterEmailApplyCode(email string) (code string, expire int, err error)
RegisterEmailApplyCode 邮件用户注册申请验证码
func (mgr *UserMgr) RegisterLAPD(uid, rawPassword string) (*User, error)
RegisterLAPD 密码用户注册
func (mgr *UserMgr) RegisterMobile(mobile, code string) (*User, error)
RegisterMobile 手机用户注册
func (mgr *UserMgr) RegisterMobileApplyCode(mobile string) (code string, expire, retry int, err error)
RegisterMobileApplyCode 手机用户注册申请验证码
func (mgr *UserMgr) RegisterTourist() (*User, error)
RegisterTourist 游客注册
func (mgr *UserMgr) LoginAuth(authName string, v interface{}) (user *User, token string, deadline int64, err error)
LoginAuth 第三方登录
func (mgr *UserMgr) LoginAuthWithFrom(authName string, v interface{}, from string) (user *User, token string, deadline int64, err error)
LoginAuthWithFrom 第三方登录 带来源
func (mgr *UserMgr) LoginLAPD(uid, rawPassword string) (user *User, token string, deadline int64, err error)
LoginLAPD 密码登录
func (mgr *UserMgr) LoginLAPDWithFrom(uid, rawPassword, from string) (user *User, token string, deadline int64, err error)
LoginLAPDWithFrom 密码登录 带来源
func (mgr *UserMgr) LoginMobile(mobile, code string) (user *User, token string, deadline int64, err error)
LoginMobile 手机验证码登录
func (mgr *UserMgr) LoginMobileApplyCode(mobile string) (code string, expire, retry int, err error)
LoginMobileApplyCode 手机验证码登录 申请验证码
func (mgr *UserMgr) LoginMobileWithFrom(mobile, code, from string) (user *User, token string, deadline int64, err error)
LoginMobileWithFrom 手机验证码登录 带来源
func (mgr *UserMgr) LoginTourist() (user *User, token string, deadline int64, err error)
LoginTourist 游客登录
func (mgr *UserMgr) LoginTouristWithFrom(from string) (user *User, token string, deadline int64, err error)
LoginTouristWithFrom 游客登录 带来源
func (mgr *UserMgr) FindUserByAny(any string) (bool, *User, error)
FindUserByAny 根据用户名/邮箱/手机号 查找用户
func (mgr *UserMgr) FindUserByAuth(authName, authUID string) (bool, *User, error)
FindUserByAuth 根据第三方认证 查找用户
func (mgr *UserMgr) FindUserByEmail(email string) (bool, *User, error)
FindUserByEmail 根据邮箱 查找用户
func (mgr *UserMgr) FindUserByMobile(mobile string) (bool, *User, error)
FindUserByMobile 根据手机号 查找用户
func (mgr *UserMgr) FindUserByUID(uid string) (bool, *User, error)
FindUserByUID 根据用户名 查找用户
func (mgr *UserMgr) VerifyToken(uid, token string) (ok bool, err error)
VerifyToken 验证token
func (mgr *UserMgr) VerifyTokenWithFrom(uid, from, token string) (ok bool, err error)
VerifyTokenWithFrom 验证token 带来源
func (mgr *UserMgr) VerifySign(uid string, accessKeyID int, data interface{}, sign string) (ok bool, err error)
VerifySign 验证sign: sign由access key和请求数据(或请求数据部分字段)计算得到
func (mgr *UserMgr) VerifyAuth(authName string, v interface{}) (authUID, authExtra string, err error)
VerifyAuth 验证第三方凭证
func (mgr *UserMgr) SetAuthMgr(args ...authmgr.AuthMgr)
SetAuthMgr 设置第三方认证
func (mgr *UserMgr) SetGenerateAccessKey(arg func() string)
SetGenerateAccessKey 设置生成accesskey的方法
func (mgr *UserMgr) SetGenerateCode(arg func() string)
SetGenerateCode 设置生成验证码的方法
func (mgr *UserMgr) SetGenerateSign(arg func(accessKey string, data interface{}) string)
SetGenerateSign 设置根据accesskey计算sign的方法
func (mgr *UserMgr) SetGenerateUID(arg func() (uid, nickname, avatar, extra string))
SetGenerateUID 设置生成用户信息的方法 如果uid格式改变,可能需要修改sql表结构
func (mgr *UserMgr) SetMLogName(name string)
SetMLogName 设置日志
func (mgr *UserMgr) SetTableAccessKey(tableName, tableCreateSQL string) error
SetTableAccessKey 设置accessKey表表名和表结构
func (mgr *UserMgr) SetTableAuth(tableName, tableCreateSQL string) error
SetTableAuth 设置第三方验证表表名和表结构
func (mgr *UserMgr) SetTableUser(tableName, tableCreateSQL string) error
SetTableUser 设置用户表表名和表结构
func (mgr *UserMgr) SetTokenMgr(arg tokenmgr.TokenMgr)
SetTokenMgr 设置token管理器
func (mgr *UserMgr) EnsureTables() error
EnsureTables 确保sql表已建立
func (mgr *UserMgr) TablesName() []string
TablesName 获得表名
func (mgr *UserMgr) TablesCreateSQL() []string
TablesCreateSQL 获得建表语句
func (mgr *UserMgr) ApplyCode(expire int, args ...interface{}) (code string, expire0 int, err error)
ApplyCode 申请一个验证码, args用来区分场景
func (mgr *UserMgr) ApplyCodeAntiReplay(lockname string, expire, retry int, args ...interface{}) (code string, expire0, retry0 int, err error)
ApplyCodeAntiReplay 申请一个防重放验证码, args用来区分场景
func (mgr *UserMgr) VerifyCode(code string, args ...interface{}) (bool, error)
VerifyCode 申请验证码 args和ApplyCode时保持一致
type User struct {
*UserData
// Has unexported fields.
}
User 用户
func (user *User) BindAuth(authName string, v interface{}) error
BindAuth 绑定第三方认证
func (user *User) Clean() error
Clean 清除用户
func (user *User) DeleteAccessKey(accessKeyID int) error
DeleteAccessKey 删除一个 access key
func (user *User) GenerateAccessKey(comment string, expireAts ...time.Time) (*UserAccessKey, error)
GenerateAccessKey 生成一个 access key
func (user *User) GetAccessKeys(isAll bool) ([]*UserAccessKey, error)
GetAccessKeys 获取accesskeys isAll 是否包含过期的访问秘钥
func (user *User) GetAuths() ([]*UserAuth, error)
GetAuths 获得第三方认证信息
func (user *User) Login() (token string, deadline int64, err error)
Login 登录
func (user *User) LoginWithFrom(from string) (token string, deadline int64, err error)
LoginWithFrom 登录 带来源
func (user *User) Logout() error
Logout 登出
func (user *User) LogoutWithFrom(from string) error
LogoutWithFrom 登出 带来源
func (user *User) UnbindAuth(authName string) error
UnbindAuth 解绑第三方认证
func (user *User) UpdateAccessKeyComment(accessKeyID int, comment string) error
UpdateAccessKeyComment 更新一个 access key 的 comment
func (user *User) UpdateAccessKeyExpireAt(accessKeyID int, expireAt *time.Time) error
UpdateAccessKeyExpireAt 更新一个 access key的超时设置 expireAt为 nil 表示永久有效
func (user *User) UpdateAuthInfo(authName, authExtra string) error
UpdateAuthInfo 更新第三方认证信息
func (user *User) UpdateEmail(email, code string) error
UpdateEmail 更新邮箱
func (user *User) UpdateEmailApplyCode() (code string, expire int, err error)
UpdateEmailApplyCode 更新邮箱申请验证码
func (user *User) UpdateInfo(nickname, avatar, extra *string) error
UpdateInfo 更新用户信息 参数可为nil, 表示不修改
func (user *User) UpdateMobile(mobile, code string) error
UpdateMobile 更新手机号
func (user *User) UpdateMobileApplyCode(mobile string) (code string, expire, retry int, err error)
UpdateMobileApplyCode 更新手机号申请验证码
func (user *User) UpdatePasswordApplyCode() (code string, expire int, err error)
UpdatePasswordApplyCode 更改密码申请验证码
func (user *User) UpdatePasswordWithCode(rawPassword, code string) error
UpdatePasswordWithCode 通过验证码更改密码
func (user *User) UpdatePasswordWithPassword(oldRawPassword, newRawPassword string) error
UpdatePasswordWithPassword 通过旧密码更改密码
func (user *User) UpdateUID(uid string) error
UpdateUID 更新uid
package main
import (
"crypto/md5"
"database/sql"
"encoding/hex"
"fmt"
"strconv"
"time"
"github.com/cheetah-fun-gs/gouser"
_ "github.com/go-sql-driver/mysql"
redigo "github.com/gomodule/redigo/redis"
)
func defaultGenerateSign(accessKey string, data interface{}) string {
ts := data.(int64)
h := md5.New()
h.Write([]byte(accessKey))
h.Write([]byte(strconv.Itoa(int(ts))))
return hex.EncodeToString(h.Sum(nil))
}
const (
testAuthName = "testAuth"
)
type testAuth struct{}
func (auth *testAuth) GetName() string {
return testAuthName
}
func (auth *testAuth) Verify(v interface{}) (uid, extra string, err error) {
uid = v.(string) + "_testAuth"
return
}
func dial() (redigo.Conn, error) {
return redigo.DialTimeout("tcp", "127.0.0.1:6379", 2*time.Second, 2*time.Second, 2*time.Second)
}
func main() {
pool := &redigo.Pool{
Dial: dial,
}
defer pool.Close()
db, err := sql.Open("mysql", "admin:admin123@tcp(127.0.0.1:3306)/test?parseTime=true&charset=utf8mb4&loc=Asia%2FShanghai")
if err != nil {
panic(err)
}
defer db.Close()
name := "demo"
secret := "tZli3W^4Rb#V"
mgr := gouser.New(name, secret, pool, db, gouser.Config{IsEnableAccessKey: true})
// 设置认证
mgr.SetAuthMgr(&testAuth{})
if err := mgr.EnsureTables(); err != nil {
panic(err)
}
for _, tableName := range mgr.TablesName() {
if _, err = db.Exec(fmt.Sprintf("truncate table %s;", tableName)); err != nil {
panic(err)
}
}
redisConn := pool.Get()
redisConn.Do("flushdb")
redisConn.Close()
// 游客注册
user, err := mgr.RegisterTourist()
if err != nil {
panic(err)
}
token, _, err := user.Login()
if err != nil {
panic(err)
}
ok, err := mgr.VerifyToken(user.UID, token)
if err != nil {
panic(err)
}
if !ok {
panic("token Verify fail")
}
// 修改uid
testuid := "test_uid"
if err = user.UpdateUID(testuid); err != nil {
panic(err)
}
ok, user, err = mgr.FindUserByUID(testuid)
if err != nil {
panic(err)
}
if !ok {
panic("testuid not found")
}
// 修改email
time.Sleep(200 * time.Millisecond)
testemail := "test123@123.com"
emailcode, _, err := user.UpdateEmailApplyCode()
if err != nil {
panic(err)
}
if err = user.UpdateEmail(testemail, emailcode); err != nil {
panic(err)
}
ok, _, err = mgr.FindUserByEmail(testemail)
if err != nil {
panic(err)
}
if !ok {
panic("testemail not found")
}
// 修改mobile
time.Sleep(200 * time.Millisecond)
testmobile := "13000000000"
mobilecode, _, _, err := user.UpdateMobileApplyCode(testmobile)
if err != nil {
panic(err)
}
if err = user.UpdateMobile(testmobile, mobilecode); err != nil {
panic(err)
}
ok, _, err = mgr.FindUserByMobile(testmobile)
if err != nil {
panic(err)
}
if !ok {
panic("testemail not found")
}
// 游客登录
user, _, _, err = mgr.LoginTourist()
if err != nil {
panic(err)
}
// accesskey
accessKey, err := user.GenerateAccessKey("test")
if err != nil {
panic(err)
}
ts := time.Now().Unix()
sign := defaultGenerateSign(accessKey.AccessKey, ts)
ok, err = mgr.VerifySign(user.UID, accessKey.ID, ts, sign)
if err != nil {
panic(err)
}
if !ok {
panic("access key Verify error")
}
// 绑定第三方
if err = user.BindAuth(testAuthName, user.UID); err != nil {
panic(err)
}
// 第三方登录
authcode := "testabc"
if _, _, _, err = mgr.LoginAuth(testAuthName, authcode); err != nil {
panic(err)
}
ok, _, err = mgr.FindUserByAuth(testAuthName, authcode+"_testAuth")
if err != nil {
panic(err)
}
if !ok {
panic("auth user not found")
}
// lapd注册
lapdUID := "test_lapd"
lapdPass := "test_lapd"
user, err = mgr.RegisterLAPD(lapdUID, lapdPass)
if err != nil {
panic(err)
}
token, _, err = user.Login()
if err != nil {
panic(err)
}
ok, err = mgr.VerifyToken(user.UID, token)
if err != nil {
panic(err)
}
if !ok {
panic("token Verify fail")
}
ok, _, err = mgr.FindUserByAny(lapdUID)
if err != nil {
panic(err)
}
if !ok {
panic("lapdUID not found")
}
// 修改密码
time.Sleep(200 * time.Millisecond)
testpassword := "test_uid123"
passwardcode, _, err := user.UpdatePasswordApplyCode()
if err != nil {
panic(err)
}
if err = user.UpdatePasswordWithCode(testpassword, passwardcode); err != nil {
panic(err)
}
if _, _, _, err = mgr.LoginLAPD(testuid, testpassword); err != nil {
panic(err)
}
// 邮箱注册
email := "test_email@abc.com"
emailcode, _, err = mgr.RegisterEmailApplyCode(email)
if err != nil {
panic(err)
}
user, err = mgr.RegisterEmail(email, emailcode)
if err != nil {
panic(err)
}
token, _, err = user.Login()
if err != nil {
panic(err)
}
ok, err = mgr.VerifyToken(user.UID, token)
if err != nil {
panic(err)
}
if !ok {
panic("token Verify fail")
}
ok, _, err = mgr.FindUserByEmail(email)
if err != nil {
panic(err)
}
if !ok {
panic("email not found")
}
// 手机注册
mobile := "13000000001"
mobilecode, _, _, err = mgr.RegisterMobileApplyCode(mobile)
if err != nil {
panic(err)
}
user, err = mgr.RegisterMobile(mobile, mobilecode)
if err != nil {
panic(err)
}
token, _, err = user.Login()
if err != nil {
panic(err)
}
ok, err = mgr.VerifyToken(user.UID, token)
if err != nil {
panic(err)
}
if !ok {
panic("token Verify fail")
}
ok, _, err = mgr.FindUserByMobile(mobile)
if err != nil {
panic(err)
}
if !ok {
panic("mobile not found")
}
// 手机直接登录
mobile = "13000000002"
mobilecode, _, _, err = mgr.LoginMobileApplyCode(mobile)
if err != nil {
panic(err)
}
user, _, _, err = mgr.LoginMobile(mobile, mobilecode)
if err != nil {
panic(err)
}
}