From c7eadfb5c90cb5833c89a2e0298e6265958502e7 Mon Sep 17 00:00:00 2001 From: tcq Date: Wed, 31 Jan 2024 17:32:39 +0800 Subject: [PATCH] user-login --- Service/rpc-service.go | 21 +++++++ Service/user-service.go | 124 +++++++++++++++++++++++++++++++++++++++- config/env.go | 12 +++- go.mod | 12 +++- go.sum | 9 +++ mysql/tables-mysql.go | 7 +++ mysql/user-mysql.go | 111 +++++++++++++++++++++++++++++++++++ redis/user-redis.go | 41 +++++++++++++ 8 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 Service/rpc-service.go create mode 100644 mysql/user-mysql.go create mode 100644 redis/user-redis.go diff --git a/Service/rpc-service.go b/Service/rpc-service.go new file mode 100644 index 0000000..df2f0ef --- /dev/null +++ b/Service/rpc-service.go @@ -0,0 +1,21 @@ +package service + +import ( + "net/rpc" + "user-srv/config" + + "github.com/sirupsen/logrus" +) + +func wechatRpcClient() (*rpc.Client, error) { + // dsn:="dingtalk:9090" + dsn := config.WECHAT_DSN + client, err := rpc.Dial("tcp", dsn) + if err != nil { + logrus.WithFields(logrus.Fields{ + "func": "rpcClient", + }).Warnf("rpc.Dial: %s", err.Error()) + return nil, err + } + return client, nil +} diff --git a/Service/user-service.go b/Service/user-service.go index c5d7dce..5d90284 100644 --- a/Service/user-service.go +++ b/Service/user-service.go @@ -2,19 +2,137 @@ package service import ( "context" + "errors" + "fmt" + "net/url" + "os" pb "user-srv/pb/api" + + "user-srv/mysql" + + "user-srv/redis" + + "github.com/sirupsen/logrus" + + "myschools.me/home-care/homecare-base/wechat" + "myschools.me/tcq/user-base/utils" ) type UserService struct { pb.UnimplementedUserServiceServer } -// 用户登录 +// 用户关注扫码登录 func (u *UserService) Login(ctx context.Context, req *pb.LoginRequest) (*pb.LoginResponse, error) { - //ToDo + //ToDo 通过获取微信二维码获取的uuid 来获取微信事件中的 + //通过 code 获取 用户openid + client, err := wechatRpcClient() + if err != nil { + return nil, err + } + + wechatUserInfoReq := &wechat.OauthUserInfoRequest{ + ID: req.Code, + } + wechatUserInfoResp := new(wechat.OauthUserInfoResponse) + if err := client.Call("Oauth.UserInfo", wechatUserInfoReq, wechatUserInfoResp); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "UserLogin", + }).Warnf("client.Call[Oauth.UserInfo]: %s", err.Error()) + return nil, err + } + //openid 不存在 + if wechatUserInfoResp.OpenID == "" { + return nil, nil + } + // + // 通过openid查找用户信息 + user, err := mysql.UserDetailByOpenId(&wechatUserInfoResp.OpenID) + if err != nil { + logrus.WithFields(logrus.Fields{ + "func": "UserLogin", + }).Warnf("mysql.UserDetail: %s", err.Error()) + return nil, err + } + + if user.ID == 0 { + go UserSendUnBindMsg(&wechatUserInfoResp.OpenID, nil) + return nil, errors.New("用户未注册,请前往公众号注册") + } + //生成用户token + token := utils.GenIDStr() + if err := redis.UserTokenSet(&token, user); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "UserLogin", + }).Warnf("redis.UserTokenSet: %s", err.Error()) + return nil, err + } + + //返回结果 + // result := struct { + // Token string + // Expire int64 + // User *model.User + // }{ + // Token: token, + // Expire: 7200, + // User: user, + // } return &pb.LoginResponse{ - Token: "12345678", + Token: token, Orgid: "1", }, nil } + +func UserSendUnBindMsg(openid, reqid *string) { + // rpc调用,发送公众号消息 + client, err := wechatRpcClient() + if err != nil { + return + } + + child := make(map[string]*wechat.TemplateDataItem) + child["thing2"] = &wechat.TemplateDataItem{ + Value: "尊敬的用户", + Color: "", + } + child["thing9"] = &wechat.TemplateDataItem{ + Value: "节能助手", + Color: "", + } + child["short_thing7"] = &wechat.TemplateDataItem{ + Value: "前往绑定", + Color: "", + } + child["character_string13"] = &wechat.TemplateDataItem{ + Value: (*reqid)[0:8], + Color: "", + } + appid := os.Getenv("WECHAT_APPID") + if appid == "" { + appid = "wxd69449ebd878fa6d" + } + redirect_uri := os.Getenv("WECHAT_REDIRECT_URI") + if redirect_uri == "" { + redirect_uri = "http://live.yyjishu.com/wechat#/bind" + } + + Url := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=", appid) + url.QueryEscape(redirect_uri) + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect" + + req := &wechat.MessageTemplateSendRequest{ + ToUser: *openid, + TemplateID: "P54vXL4yOpmyMzk4x3-VpIDMSq4u5sBM-IDApMXP_WE", + URL: Url, + Color: "", + Data: child, + } + resp := new(wechat.MessageTemplateSendResponse) + if err := client.Call("Message.TemplateSend", req, resp); err != nil { + logrus.WithFields(logrus.Fields{ + "func": "UserSendUnBindMsg", + "reqid": *reqid, + }).Warnf("client.Call[Message.TemplateSend]: %s", err.Error()) + return + } +} diff --git a/config/env.go b/config/env.go index 1779328..00b3f77 100644 --- a/config/env.go +++ b/config/env.go @@ -18,6 +18,7 @@ var ( RedisHost string RedisPassword string RedisDB int + WECHAT_DSN string ) func ConfigInit() { @@ -90,7 +91,7 @@ func ConfigInit() { MYSQL_HOST = func() string { host := os.Getenv("MYSQL_HOST") if host == "" { - host = "root:123456@tcp(127.0.0.1:3306)/ceshi?charset=utf8mb4&parseTime=True&loc=Local" + host = "root:123456@tcp(127.0.0.1:3306)/grpc?charset=utf8mb4&parseTime=True&loc=Local" } return host }() @@ -118,4 +119,13 @@ func ConfigInit() { return db }() + //微信 + WECHAT_DSN = func() string { + dsn := os.Getenv("WECHAT_DSN") + if dsn == "" { + dsn = "127.0.0.1:9091" + } + return dsn + }() + } diff --git a/go.mod b/go.mod index 96aebda..412f631 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module user-srv -go 1.21.1 +go 1.21.4 + +toolchain go1.21.6 require ( github.com/gomodule/redigo v1.8.9 @@ -17,6 +19,11 @@ require ( gorm.io/plugin/dbresolver v1.5.0 ) +require ( + github.com/bwmarrin/snowflake v0.3.0 // indirect + myschools.me/home-care/homecare-base v0.0.0-20240117071311-7c63d4cc0d29 // indirect +) + require ( github.com/armon/go-metrics v0.4.1 // indirect github.com/fatih/color v1.14.1 // indirect @@ -35,7 +42,7 @@ require ( github.com/jonboulle/clockwork v0.4.0 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -45,4 +52,5 @@ require ( golang.org/x/text v0.14.0 // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect + myschools.me/tcq/user-base v0.0.0-20240131081333-dd818f008c5f ) diff --git a/go.sum b/go.sum index 2276fe1..67136d5 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= @@ -133,6 +135,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= @@ -232,6 +236,7 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -277,3 +282,7 @@ gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A= gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gorm.io/plugin/dbresolver v1.5.0 h1:XVHLxh775eP0CqVh3vcfJtYqja3uFl5Wr3cKlY8jgDY= gorm.io/plugin/dbresolver v1.5.0/go.mod h1:l4Cn87EHLEYuqUncpEeTC2tTJQkjngPSD+lo8hIvcT0= +myschools.me/home-care/homecare-base v0.0.0-20240117071311-7c63d4cc0d29 h1:/EuDrMBkasENuc4DAyUEvJMNXC0QYVLyH9SiJWHu4Jk= +myschools.me/home-care/homecare-base v0.0.0-20240117071311-7c63d4cc0d29/go.mod h1:70trCTlFSgoggPL1S0i1yDRfvVxOHqNwU9Bu9guPJkI= +myschools.me/tcq/user-base v0.0.0-20240131081333-dd818f008c5f h1:2Z0FSZHBBVzek2KYPbowRYcnINI7cqGMRQSaQeVGknM= +myschools.me/tcq/user-base v0.0.0-20240131081333-dd818f008c5f/go.mod h1:oq0aFBhUz53bA7nOL1kkmUAzCnf49PlcU13qXChqPfI= diff --git a/mysql/tables-mysql.go b/mysql/tables-mysql.go index e851345..34daa57 100644 --- a/mysql/tables-mysql.go +++ b/mysql/tables-mysql.go @@ -1,10 +1,17 @@ package mysql +import ( + model "myschools.me/tcq/user-base/model" +) + func InitTable() error { //不初始化表时返回 if !_conf.InitTable { return nil } + //初始表 + db, _ := New() + db.AutoMigrate(&model.User{}) //成功初始化后返回 return nil diff --git a/mysql/user-mysql.go b/mysql/user-mysql.go new file mode 100644 index 0000000..8a2c0f3 --- /dev/null +++ b/mysql/user-mysql.go @@ -0,0 +1,111 @@ +package mysql + +import ( + "gorm.io/gorm" + model "myschools.me/tcq/user-base/model" +) + +func UserDetailByOpenId(openid *string) (user *model.User, err error) { + db, _ := New() + user = &model.User{} + if err := db.Where("openid = ?", *openid).First(user).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, err + } + } + return user, nil +} + +func UserDetailById(id *uint, db *gorm.DB) (user *model.User, err error) { + + if db == nil { + db, _ = New() + } + user = &model.User{} + if err := db.Where("id = ?", *id).First(user).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, err + } + } + return user, nil +} + +func UserDetailByMobile(mobile *string, db *gorm.DB) (user *model.User, err error) { + + if db == nil { + db, _ = New() + } + user = &model.User{} + if err := db.Where("mobile = ?", *mobile).First(user).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, err + } + } + return user, nil +} + +func UserCreate(username, mobile, role, projectid *string, db *gorm.DB) (*model.User, error) { + if db == nil { + db, _ = New() + } + user := &model.User{ + UserName: *username, + Mobile: *mobile, + Role: *role, + ProjectID: *projectid, + } + if err := db.Create(user).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, err + } + } + return user, nil +} + +func UserUpdate(user *model.User, db *gorm.DB) error { + + if db == nil { + db, _ = New() + } + if err := db.Model(&model.User{}).Where("id=?", user.ID).Updates(user).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return err + } + } + return nil +} + +func UserDelete(userid *uint) error { + db, _ := New() + if err := db.Where("id=?", *userid).Delete(&model.User{}).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return err + } + } + return nil +} + +func UserList(index, size int, name, role string) ([]*model.User, int64, error) { + db, _ := New() + users := make([]*model.User, 0) + var count int64 + query := db.Model(&model.User{}) + if name != "" { + query.Where("user_name like ?", "%"+name+"%") + } + if role != "" { + query.Where("role = ?", role) + } + if err := query.Count(&count).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, 0, err + } + } + if err := query.Offset((index - 1) * size).Limit(size).Find(&users).Error; err != nil { + if err != gorm.ErrRecordNotFound { + return nil, 0, err + } + } + + return users, count, nil +} diff --git a/redis/user-redis.go b/redis/user-redis.go new file mode 100644 index 0000000..b717185 --- /dev/null +++ b/redis/user-redis.go @@ -0,0 +1,41 @@ +package redis + +import ( + "encoding/json" + "errors" + "time" + + "github.com/sirupsen/logrus" + "myschools.me/tcq/user-base/model" +) + +// 存储用户的Token +func UserTokenSet(key *string, usr *model.User) error { + + err := Set(*key, usr, 7210*time.Second) + if err != nil { + logrus.WithFields(logrus.Fields{ + "func": "UserTokenSet", + }).Warnf("Set: %s", err.Error()) + return err + } + return nil +} + +// 从redis中获取用户信息,最佳实践经验建议把此代码放service层 +func UserTokenGet(token *string) (*model.User, error) { + b, err := GetBytes(token) + if err != nil { + return nil, err + } + + if b == nil { + return nil, errors.New("无效token,请重新登录!") + } + + var user *model.User + if err := json.Unmarshal(*b, &user); err != nil { + return nil, err + } + return user, nil +}