diff --git a/.gitignore b/.gitignore index 723ef36..5e5da64 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +data/ \ No newline at end of file diff --git a/game_open_api/app_user.api b/game_open_api/app_user.api index c33064c..cc554b3 100644 --- a/game_open_api/app_user.api +++ b/game_open_api/app_user.api @@ -11,7 +11,6 @@ type UserId { } type SetAppUserRequest { - Id uint64 `json:"id"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` } @@ -19,6 +18,7 @@ type SetAppUserRequest { @server ( group: app_user prefix: /v1/app_user + jwt: Auth // 开启 jwt 认证 timeout: 3s // 对当前 Foo 语法块下的所有路由进行超时配置,不需要则请删除此行 maxBytes: 1048576 // 对当前 Foo 语法块下的所有路由添加请求体大小控制,单位为 byte,goctl 版本 >= 1.5.0 才支持 ) diff --git a/game_open_api/douyin.api b/game_open_api/douyin.api index e9fbeac..48657ca 100644 --- a/game_open_api/douyin.api +++ b/game_open_api/douyin.api @@ -7,12 +7,6 @@ type DouyinCode2UserIdRequest { AnonymousCode string `form:"anonymousCode,optional"` } -type GetEcpmRequest { - AppId string `form:"appId"` - UserId uint64 `form:"userId"` -} - - @server( group: douyin prefix: /v1/douyin // 对当前 Foo 语法块下的所有路由,新增 /v1 路由前缀,不需要则请删除此行 @@ -21,10 +15,24 @@ type GetEcpmRequest { ) service game_open_api-api { - @handler douyinCode2UserId - get /code2userId (DouyinCode2UserIdRequest) returns (int64) - @handler getEcpm - get /getEcpm (GetEcpmRequest) returns (bool) + @handler douyinCode2UserId + get /code2userId (DouyinCode2UserIdRequest) returns (string) + +} + +@server( + group: douyin + prefix: /v1/douyin // 对当前 Foo 语法块下的所有路由,新增 /v1 路由前缀,不需要则请删除此行 + jwt: Auth // 开启 jwt 认证 + timeout: 3s // 对当前 Foo 语法块下的所有路由进行超时配置,不需要则请删除此行 + maxBytes: 1048576 // 对当前 Foo 语法块下的所有路由添加请求体大小控制,单位为 byte,goctl 版本 >= 1.5.0 才支持 +) + +service game_open_api-api { + + @handler getEcpm + get /getEcpm returns (bool) + } diff --git a/game_open_api/etc/gameopenapi-api.yaml b/game_open_api/etc/gameopenapi-api.yaml index 9a0bc76..288f8c4 100644 --- a/game_open_api/etc/gameopenapi-api.yaml +++ b/game_open_api/etc/gameopenapi-api.yaml @@ -6,3 +6,7 @@ DB: Cache: - Host: 127.0.0.1:6379 type: node + +Auth: + AccessSecret: youtu123! + AccessExpire: 3600 diff --git a/game_open_api/game.api b/game_open_api/game.api index 436688a..06f96c2 100644 --- a/game_open_api/game.api +++ b/game_open_api/game.api @@ -4,14 +4,13 @@ syntax = "v1" type SetUserGameScoreRequest { - AppId string `json:"appId"` Score uint64 `json:"score"` - UserId uint64 `json:"userId"` } @server ( group: game prefix: /v1/game // 对当前 Foo 语法块下的所有路由,新增 /v1 路由前缀,不需要则请删除此行 + jwt: Auth // 开启 jwt 认证 timeout: 3s // 对当前 Foo 语法块下的所有路由进行超时配置,不需要则请删除此行 maxBytes: 1048576 // 对当前 Foo 语法块下的所有路由添加请求体大小控制,单位为 byte,goctl 版本 >= 1.5.0 才支持 ) diff --git a/game_open_api/internal/config/config.go b/game_open_api/internal/config/config.go index 10b20d9..fa1f610 100644 --- a/game_open_api/internal/config/config.go +++ b/game_open_api/internal/config/config.go @@ -12,4 +12,9 @@ type Config struct { DataSource string } Cache cache.CacheConf + + Auth struct { // JWT 认证需要的密钥和过期时间配置 + AccessSecret string + AccessExpire int64 + } } diff --git a/game_open_api/internal/handler/douyin/getEcpmHandler.go b/game_open_api/internal/handler/douyin/getEcpmHandler.go index 9241ffe..a00de52 100644 --- a/game_open_api/internal/handler/douyin/getEcpmHandler.go +++ b/game_open_api/internal/handler/douyin/getEcpmHandler.go @@ -6,19 +6,13 @@ import ( "github.com/zeromicro/go-zero/rest/httpx" "youtu_server/game_open_api/internal/logic/douyin" "youtu_server/game_open_api/internal/svc" - "youtu_server/game_open_api/internal/types" ) func GetEcpmHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var req types.GetEcpmRequest - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) - return - } l := douyin.NewGetEcpmLogic(r.Context(), svcCtx) - resp, err := l.GetEcpm(&req) + resp, err := l.GetEcpm() if err != nil { httpx.ErrorCtx(r.Context(), w, err) } else { diff --git a/game_open_api/internal/handler/routes.go b/game_open_api/internal/handler/routes.go index 41dc5b5..80c2ab5 100644 --- a/game_open_api/internal/handler/routes.go +++ b/game_open_api/internal/handler/routes.go @@ -25,6 +25,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Handler: app_user.AppUserSetUserHandler(serverCtx), }, }, + rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/v1/app_user"), rest.WithTimeout(3000*time.Millisecond), rest.WithMaxBytes(1048576), @@ -37,12 +38,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/code2userId", Handler: douyin.DouyinCode2UserIdHandler(serverCtx), }, + }, + rest.WithPrefix("/v1/douyin"), + rest.WithTimeout(3000*time.Millisecond), + rest.WithMaxBytes(1048576), + ) + + server.AddRoutes( + []rest.Route{ { Method: http.MethodGet, Path: "/getEcpm", Handler: douyin.GetEcpmHandler(serverCtx), }, }, + rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/v1/douyin"), rest.WithTimeout(3000*time.Millisecond), rest.WithMaxBytes(1048576), @@ -61,6 +71,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Handler: game.RankingSetScoreHandler(serverCtx), }, }, + rest.WithJwt(serverCtx.Config.Auth.AccessSecret), rest.WithPrefix("/v1/game"), rest.WithTimeout(3000*time.Millisecond), rest.WithMaxBytes(1048576), diff --git a/game_open_api/internal/logic/app_user/appUserSetUserLogic.go b/game_open_api/internal/logic/app_user/appUserSetUserLogic.go index 610b191..1a0f80a 100644 --- a/game_open_api/internal/logic/app_user/appUserSetUserLogic.go +++ b/game_open_api/internal/logic/app_user/appUserSetUserLogic.go @@ -25,9 +25,12 @@ func NewAppUserSetUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Ap } func (l *AppUserSetUserLogic) AppUserSetUser(req *types.SetAppUserRequest) (resp *types.UserId, err error) { - // todo: add your logic here and delete this line + at, err := svc.GetCtxToken(l.ctx) + if err != nil { + return + } err = l.svcCtx.AppUser.UpdateNicknameAvatar(l.ctx, &model.AppUser{ - Id: req.Id, + Id: at.UserId, Nickname: req.Nickname, Avatar: req.Avatar, }) diff --git a/game_open_api/internal/logic/douyin/douyinCode2UserIdLogic.go b/game_open_api/internal/logic/douyin/douyinCode2UserIdLogic.go index 6530b48..bdd897c 100644 --- a/game_open_api/internal/logic/douyin/douyinCode2UserIdLogic.go +++ b/game_open_api/internal/logic/douyin/douyinCode2UserIdLogic.go @@ -3,6 +3,8 @@ package douyin import ( "context" "errors" + "github.com/golang-jwt/jwt/v4" + "time" "youtu_server/game_open_api/internal/app_api_helper" "youtu_server/game_open_api/model" @@ -27,7 +29,7 @@ func NewDouyinCode2UserIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) } } -func (l *DouyinCode2UserIdLogic) DouyinCode2UserId(req *types.DouyinCode2UserIdRequest) (resp int64, err error) { +func (l *DouyinCode2UserIdLogic) DouyinCode2UserId(req *types.DouyinCode2UserIdRequest) (resp string, err error) { douyinCli, err := app_api_helper.DouyinCli.GetDouYinOpenApi(req.AppId) if err != nil { return @@ -54,6 +56,29 @@ func (l *DouyinCode2UserIdLogic) DouyinCode2UserId(req *types.DouyinCode2UserIdR Unionid: res.Unionid, AnonymousOpenid: res.AnonymousOpenid, } - _, err = l.svcCtx.AppUser.Insert(l.ctx, aui) + result, err := l.svcCtx.AppUser.Insert(l.ctx, aui) + if err != nil { + return + } + + id, err := result.LastInsertId() + if err != nil { + return + } + aui.Id = uint64(id) + + claims := make(jwt.MapClaims) + claims["exp"] = time.Now().Unix() + l.svcCtx.Config.Auth.AccessExpire + claims["iat"] = l.svcCtx.Config.Auth.AccessExpire + + claims["payload"] = &svc.AccessToken{ + AppId: accountId, + UserId: aui.Id, + AppIdStr: req.AppId, + OpenId: res.Openid, + } + token := jwt.New(jwt.SigningMethodHS256) + token.Claims = claims + resp, err = token.SignedString([]byte(l.svcCtx.Config.Auth.AccessSecret)) return } diff --git a/game_open_api/internal/logic/douyin/getEcpmLogic.go b/game_open_api/internal/logic/douyin/getEcpmLogic.go index 1189335..932883f 100644 --- a/game_open_api/internal/logic/douyin/getEcpmLogic.go +++ b/game_open_api/internal/logic/douyin/getEcpmLogic.go @@ -5,10 +5,8 @@ import ( "time" "youtu_server/game_open_api/internal/app_api_helper" - "youtu_server/game_open_api/internal/svc" - "youtu_server/game_open_api/internal/types" - "github.com/zeromicro/go-zero/core/logx" + "youtu_server/game_open_api/internal/svc" ) type GetEcpmLogic struct { @@ -26,14 +24,15 @@ func NewGetEcpmLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetEcpmLo } } -func (l *GetEcpmLogic) GetEcpm(req *types.GetEcpmRequest) (result bool, errNeverNil error) { - user, err := l.svcCtx.AppUser.FindOne(l.ctx, req.UserId) +func (l *GetEcpmLogic) GetEcpm() (result bool, errNeverNil error) { + + at, err := svc.GetCtxToken(l.ctx) if err != nil { - l.Logger.Error(err.Error()) + errNeverNil = err return } - res, err := app_api_helper.DouyinCli.GetEcpmData(req.AppId, user.Openid, time.Now().Format(time.DateOnly)) + res, err := app_api_helper.DouyinCli.GetEcpmData(at.AppIdStr, at.OpenId, time.Now().Format(time.DateOnly)) if err != nil { l.Logger.Error(err.Error()) return @@ -45,7 +44,7 @@ func (l *GetEcpmLogic) GetEcpm(req *types.GetEcpmRequest) (result bool, errNever return } - if ecpm > float64(app_api_helper.DouyinCli.GetEcpmValue(req.AppId)) && len(res) > int(app_api_helper.DouyinCli.GetEcpmViewCount(req.AppId)) { + if ecpm > float64(app_api_helper.DouyinCli.GetEcpmValue(at.AppIdStr)) && len(res) > int(app_api_helper.DouyinCli.GetEcpmViewCount(at.AppIdStr)) { result = true } else { result = false diff --git a/game_open_api/internal/logic/game/rankingSetScoreLogic.go b/game_open_api/internal/logic/game/rankingSetScoreLogic.go index bd31a31..3cfb455 100644 --- a/game_open_api/internal/logic/game/rankingSetScoreLogic.go +++ b/game_open_api/internal/logic/game/rankingSetScoreLogic.go @@ -25,13 +25,13 @@ func NewRankingSetScoreLogic(ctx context.Context, svcCtx *svc.ServiceContext) *R } func (l *RankingSetScoreLogic) RankingSetScore(req *types.SetUserGameScoreRequest) error { - appId, err := l.svcCtx.AppAccount.FindIdByAppId(l.ctx, req.AppId) + at, err := svc.GetCtxToken(l.ctx) if err != nil { return err } _, err = l.svcCtx.GameScore.Insert(l.ctx, &model.GameScore{ - AppUserId: req.UserId, - AppAccount: appId, + AppUserId: at.UserId, + AppAccount: at.AppId, Score: req.Score, }) diff --git a/game_open_api/internal/logic/wechat/wechatCode2UserIdLogic.go b/game_open_api/internal/logic/wechat/wechatCode2UserIdLogic.go index fb31552..bb0366b 100644 --- a/game_open_api/internal/logic/wechat/wechatCode2UserIdLogic.go +++ b/game_open_api/internal/logic/wechat/wechatCode2UserIdLogic.go @@ -3,6 +3,8 @@ package wechat import ( "context" "errors" + "github.com/golang-jwt/jwt/v4" + "time" "youtu_server/game_open_api/internal/app_api_helper" "youtu_server/game_open_api/model" @@ -27,7 +29,7 @@ func NewWechatCode2UserIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) } } -func (l *WechatCode2UserIdLogic) WechatCode2UserId(req *types.WechatCode2UserIdRequest) (resp uint64, err error) { +func (l *WechatCode2UserIdLogic) WechatCode2UserId(req *types.WechatCode2UserIdRequest) (resp string, err error) { wechatCli, err := app_api_helper.WechatCli.GetWechatOpenApi(req.AppId) if err != nil { return @@ -56,7 +58,30 @@ func (l *WechatCode2UserIdLogic) WechatCode2UserId(req *types.WechatCode2UserIdR //todo 校验唯一 - _, err = l.svcCtx.AppUser.Insert(l.ctx, aui) + result, err := l.svcCtx.AppUser.Insert(l.ctx, aui) + if err != nil { + return + } + + id, err := result.LastInsertId() + if err != nil { + return + } + aui.Id = uint64(id) + + claims := make(jwt.MapClaims) + claims["exp"] = time.Now().Unix() + l.svcCtx.Config.Auth.AccessExpire + claims["iat"] = l.svcCtx.Config.Auth.AccessExpire + + claims["payload"] = &svc.AccessToken{ + AppId: accountId, + UserId: aui.Id, + AppIdStr: req.AppId, + OpenId: res.OpenID, + } + token := jwt.New(jwt.SigningMethodHS256) + token.Claims = claims + resp, err = token.SignedString([]byte(l.svcCtx.Config.Auth.AccessSecret)) return } diff --git a/game_open_api/internal/svc/serviceContext.go b/game_open_api/internal/svc/serviceContext.go new file mode 100644 index 0000000..6b5d119 --- /dev/null +++ b/game_open_api/internal/svc/serviceContext.go @@ -0,0 +1,52 @@ +package svc + +import ( + "context" + "encoding/json" + "errors" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "youtu_server/game_open_api/internal/config" + "youtu_server/game_open_api/model" +) + +type ServiceContext struct { + Config config.Config + AppUser model.AppUserModel + GameScore model.GameScoreModel + AppAccount model.AppAccountModel +} + +func NewServiceContext(c config.Config) *ServiceContext { + return &ServiceContext{ + Config: c, + AppUser: model.NewAppUserModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), + GameScore: model.NewGameScoreModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), + AppAccount: model.NewAppAccountModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), + } +} + +type AccessToken struct { + AppId uint64 `json:"appId"` + UserId uint64 `json:"userId"` + AppIdStr string `json:"appIdStr"` + OpenId string `json:"openId"` +} + +func UnmarshalAccessToken(d any) (ac AccessToken, err error) { + m, ok := d.(map[string]interface{}) + if !ok { + err = errors.New("invalid access token") + return + } + appId, _ := m["appId"].(json.Number).Int64() + ac.AppId = uint64(appId) + userId, _ := m["userId"].(json.Number).Int64() + ac.UserId = uint64(userId) + ac.AppIdStr = m["appIdStr"].(string) + ac.OpenId = m["openId"].(string) + return +} + +func GetCtxToken(ctx context.Context) (ac AccessToken, err error) { + return UnmarshalAccessToken(ctx.Value("payload")) +} diff --git a/game_open_api/internal/svc/servicecontext.go b/game_open_api/internal/svc/servicecontext.go deleted file mode 100644 index 5d90423..0000000 --- a/game_open_api/internal/svc/servicecontext.go +++ /dev/null @@ -1,23 +0,0 @@ -package svc - -import ( - "github.com/zeromicro/go-zero/core/stores/sqlx" - "youtu_server/game_open_api/internal/config" - "youtu_server/game_open_api/model" -) - -type ServiceContext struct { - Config config.Config - AppUser model.AppUserModel - GameScore model.GameScoreModel - AppAccount model.AppAccountModel -} - -func NewServiceContext(c config.Config) *ServiceContext { - return &ServiceContext{ - Config: c, - AppUser: model.NewAppUserModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), - GameScore: model.NewGameScoreModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), - AppAccount: model.NewAppAccountModel(sqlx.NewMysql(c.DB.DataSource), c.Cache), - } -} diff --git a/game_open_api/internal/types/types.go b/game_open_api/internal/types/types.go index ee10e88..f63af4e 100644 --- a/game_open_api/internal/types/types.go +++ b/game_open_api/internal/types/types.go @@ -9,21 +9,13 @@ type DouyinCode2UserIdRequest struct { AnonymousCode string `form:"anonymousCode,optional"` } -type GetEcpmRequest struct { - AppId string `form:"appId"` - UserId uint64 `form:"userId"` -} - type SetAppUserRequest struct { - Id uint64 `json:"id"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` } type SetUserGameScoreRequest struct { - AppId string `json:"appId"` - Score uint64 `json:"score"` - UserId uint64 `json:"userId"` + Score uint64 `json:"score"` } type UserId struct { diff --git a/game_open_api/wechat.api b/game_open_api/wechat.api index fb5f879..313b576 100644 --- a/game_open_api/wechat.api +++ b/game_open_api/wechat.api @@ -15,6 +15,6 @@ type WechatCode2UserIdRequest { service game_open_api-api { @handler wechatCode2UserId - get /code2userId (WechatCode2UserIdRequest) returns (uint64 ) + get /code2userId (WechatCode2UserIdRequest) returns (string ) }