jwt鉴权

This commit is contained in:
xiabin 2025-01-20 10:10:08 +08:00
parent 271dd8671f
commit a9403daab5
17 changed files with 166 additions and 71 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.idea
data/

View File

@ -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 才支持
)

View File

@ -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)
}

View File

@ -6,3 +6,7 @@ DB:
Cache:
- Host: 127.0.0.1:6379
type: node
Auth:
AccessSecret: youtu123!
AccessExpire: 3600

View File

@ -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 才支持
)

View File

@ -12,4 +12,9 @@ type Config struct {
DataSource string
}
Cache cache.CacheConf
Auth struct { // JWT 认证需要的密钥和过期时间配置
AccessSecret string
AccessExpire int64
}
}

View File

@ -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 {

View File

@ -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),

View File

@ -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,
})

View File

@ -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
}

View File

@ -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

View File

@ -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,
})

View File

@ -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
}

View File

@ -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"))
}

View File

@ -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),
}
}

View File

@ -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 {

View File

@ -15,6 +15,6 @@ type WechatCode2UserIdRequest {
service game_open_api-api {
@handler wechatCode2UserId
get /code2userId (WechatCode2UserIdRequest) returns (uint64 )
get /code2userId (WechatCode2UserIdRequest) returns (string )
}