diff --git a/ddl/fs_guest.sql b/ddl/fs_guest.sql new file mode 100644 index 00000000..980b268d --- /dev/null +++ b/ddl/fs_guest.sql @@ -0,0 +1,17 @@ +-- fusentest.fs_guest definition + + + +CREATE TABLE `fs_guest` ( + `guest_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '游客ID', + `auth_key` varchar(512) NOT NULL DEFAULT '' COMMENT 'jwt token', + `status` tinyint(3) unsigned DEFAULT '1' COMMENT '1正常 0不正常', + `is_del` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否删除 1删除', + `created_at` int(11) NOT NULL DEFAULT '0' COMMENT '添加时间', + `updated_at` int(11) NOT NULL DEFAULT '0' COMMENT '更新时间', + `is_open_render` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否打开个性化渲染(1:开启,0:关闭)', + `is_thousand_face` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已经存在千人千面(1:存在,0:不存在)', + `is_low_rendering` tinyint(1) unsigned zerofill NOT NULL DEFAULT '0' COMMENT '是否开启低渲染模型渲染', + `is_remove_bg` tinyint(1) NOT NULL DEFAULT '1' COMMENT '用户上传logo是否去除背景', + PRIMARY KEY (`guest_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='游客表'; \ No newline at end of file diff --git a/fs_gen_mysql_model.sh b/fs_gen_mysql_model.sh index 95bf5fbd..81e4550e 100755 --- a/fs_gen_mysql_model.sh +++ b/fs_gen_mysql_model.sh @@ -1,2 +1,4 @@ #! /bin/bash -goctl model mysql ddl --src ./ddl/$1.sql --dir model/ --home ./goctl_template \ No newline at end of file +# goctl model mysql ddl --src ./ddl/$1.sql --dir model/ --home ./goctl_template + +go run generator/main.go -name $1 \ No newline at end of file diff --git a/generator/main.go b/generator/main.go new file mode 100644 index 00000000..9c4aa703 --- /dev/null +++ b/generator/main.go @@ -0,0 +1,232 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + + "github.com/zeromicro/ddl-parser/parser" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +var targerDir = "ddl" +var genDir = "model/gmodel_gen" + +func toPascalCase(s string) string { + words := strings.Split(s, "_") + for i, word := range words { + words[i] = cases.Title(language.English).String(strings.ToLower(word)) + } + return strings.Join(words, "") +} + +const ( + _ int = iota + LongVarBinary + LongVarChar + GeometryCollection + GeomCollection + LineString + MultiLineString + MultiPoint + MultiPolygon + Point + Polygon + Json + Geometry + Enum + Set + Bit + Time + Timestamp + DateTime + Binary + VarBinary + Blob + Year + Decimal + Dec + Fixed + Numeric + Float + Float4 + Float8 + Double + Real + TinyInt + SmallInt + MediumInt + Int + Integer + BigInt + MiddleInt + Int1 + Int2 + Int3 + Int4 + Int8 + Date + TinyBlob + MediumBlob + LongBlob + Bool + Boolean + Serial + NVarChar + NChar + Char + Character + VarChar + TinyText + Text + MediumText + LongText +) + +var SQLTypeToGoTypeMap = map[int]string{ + LongVarBinary: "[]byte", + Binary: "[]byte", + VarBinary: "[]byte", + Blob: "[]byte", + TinyBlob: "[]byte", + MediumBlob: "[]byte", + LongBlob: "[]byte", + + LongVarChar: "*string", + NVarChar: "*string", + NChar: "*string", + Char: "*string", + Character: "*string", + VarChar: "*string", + TinyText: "*string", + Text: "*string", + MediumText: "*string", + LongText: "*string", + + Time: "*time.Time", + Timestamp: "*time.Time", + DateTime: "*time.Time", + Date: "*time.Time", + + Year: "*int64", + TinyInt: "*int64", + SmallInt: "*int64", + MediumInt: "*int64", + Int: "*int64", + Integer: "*int64", + BigInt: "*int64", + MiddleInt: "*int64", + Int1: "*int64", + Int2: "*int64", + Int3: "*int64", + Int4: "*int64", + Int8: "*int64", + Serial: "*int64", + + Decimal: "*float64", + Dec: "*float64", + Fixed: "*float64", + Numeric: "*float64", + Float: "*float64", + Float4: "*float64", + Float8: "*float64", + Double: "*float64", + Real: "*float64", + + Bool: "*bool", + Boolean: "*bool", +} + +func main() { + var name string + flag.StringVar(&name, "name", "", "输入需要序列化的ddl文件名, 不需要后缀.ddl") + flag.Parse() + + p, err := filepath.Abs(fmt.Sprintf("%s/%s.sql", targerDir, name)) + if err != nil { + panic(err) + } + + ddlf, err := os.Open(p) + if err != nil { + panic(err) + } + ddlfilestr, err := ioutil.ReadAll(ddlf) + if err != nil { + panic(err) + } + // PRIMARY KEY (`guest_id`) USING BTREE + re := regexp.MustCompile("PRIMARY\\s+KEY\\s+\\(\\s*`([^`]+)`\\s*\\)|`([^`]+)` [^\n]+PRIMARY\\s+KEY\\s+") + matches := re.FindStringSubmatch(string(ddlfilestr)) + PrimaryStr := "" + if len(matches) > 0 { + PrimaryStr = matches[1] + } + + // 匹配到主键定义 + + parser.NewParser() + result, err := parser.NewParser().From(p) + if err != nil { + panic(err) + } + + fcontent := "package model\nimport \"gorm.io/gorm\"\n" + + for _, table := range result { + structstr := "type %s struct {%s\n}\n" + + tableName := toPascalCase(table.Name) + + fieldstr := "" + for _, col := range table.Columns { + fieldName := toPascalCase(col.Name) + typeName := SQLTypeToGoTypeMap[col.DataType.Type()] + tagstr := "`gorm:" + if col.Name == PrimaryStr { + tagstr += "\"primary_key\"" + typeName = typeName[1:] + } else { + tagstr += "\"\"" + } + tagstr += fmt.Sprintf(" json:\"%s\"`", col.Name) + + fieldColStr := fmt.Sprintf("\n%s %s %s// %s", fieldName, typeName, tagstr, col.Constraint.Comment) + + fieldstr += fieldColStr + + } + + fcontent += fmt.Sprintf(structstr, tableName, fieldstr) + modelstr := fmt.Sprintf(`type %sModel struct {db *gorm.DB}`, tableName) + fcontent += modelstr + fcontent += "\n" + + newfuncstr := fmt.Sprintf(`func New%sModel(db *gorm.DB) *%sModel {return &%sModel{db}}`, tableName, tableName, tableName) + fcontent += newfuncstr + fcontent += "\n" + + genGoFileName := fmt.Sprintf("%s/%s_gen.go", genDir, table.Name) + f, err := os.OpenFile(genGoFileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } + f.WriteString(fcontent) + err = f.Close() + if err != nil { + panic(err) + } + err = exec.Command("gofmt", "-w", genGoFileName).Run() + if err != nil { + panic(err) + } + // log.Println(fcontent) + } +} diff --git a/generator/main_test.go b/generator/main_test.go new file mode 100644 index 00000000..0cd5ac49 --- /dev/null +++ b/generator/main_test.go @@ -0,0 +1,15 @@ +package main + +import ( + "os" + "testing" +) + +func TestMain(t *testing.T) { + // args := []string{"-name", "fs_guest"} + targerDir = "../" + targerDir + genDir = "../" + genDir + os.Args = []string{"cmd", "-name=fs_guest"} + + main() +} diff --git a/go.mod b/go.mod index 851f7f5b..2903f6e0 100644 --- a/go.mod +++ b/go.mod @@ -12,11 +12,16 @@ require ( gorm.io/gorm v1.25.1 ) +require ( + github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec // indirect + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect +) + require ( github.com/474420502/requests v1.32.1 github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/tidwall/gjson v1.12.0 // indirect + github.com/tidwall/gjson v1.12.0 github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect ) @@ -47,6 +52,7 @@ require ( github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/zeromicro/ddl-parser v1.0.4 go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.14.0 // indirect @@ -60,7 +66,7 @@ require ( go.uber.org/automaxprocs v1.5.2 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/text v0.9.0 google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197 // indirect google.golang.org/grpc v1.54.0 // indirect google.golang.org/protobuf v1.30.0 // indirect diff --git a/go.sum b/go.sum index 27c0ccde..417ae23c 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/miniredis/v2 v2.30.2 h1:lc1UAUT9ZA7h4srlfBmBt2aorm5Yftk9nBjxz7EyY9I= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec h1:EEyRvzmpEUZ+I8WmD5cw/vY8EqhambkOqy5iFr0908A= +github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210521184019-c5ad59b459ec/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= @@ -178,6 +180,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -235,6 +239,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/zeromicro/ddl-parser v1.0.4 h1:fzU0ZNfV/a6T/WO8TvZZeJE9hmdt3qHvVUsW1X9SGJQ= +github.com/zeromicro/ddl-parser v1.0.4/go.mod h1:ISU/8NuPyEpl9pa17Py9TBPetMjtsiHrb9f5XGiYbo8= github.com/zeromicro/go-zero v1.5.2 h1:vpMlZacCMtgdtYzKI3OMyhS6mZ9UQctiAh0J7gIq31I= github.com/zeromicro/go-zero v1.5.2/go.mod h1:ndCd1nMMAdEMZgPfdm1fpavHUdBW0ykB6ckCRaSG10w= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/goctl_template/api/handler.tpl b/goctl_template/api/handler.tpl index 3da5520e..3b228256 100644 --- a/goctl_template/api/handler.tpl +++ b/goctl_template/api/handler.tpl @@ -15,28 +15,40 @@ import ( func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } {{if .HasRequest}}var req types.{{.RequestType}} @@ -53,7 +65,6 @@ func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx) {{if .HasResp}}resp{{end}} := l.{{.Call}}({{if .HasRequest}}&req, {{end}}userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { {{if .HasResp}}httpx.OkJsonCtx(r.Context(), w, resp){{else}}httpx.Ok(w){{end}} } else { diff --git a/model/fsguestmodel.go b/model/fsguestmodel.go new file mode 100755 index 00000000..f3f3dc68 --- /dev/null +++ b/model/fsguestmodel.go @@ -0,0 +1,24 @@ +package model + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var _ FsGuestModel = (*customFsGuestModel)(nil) + +type ( + // FsGuestModel is an interface to be customized, add more methods here, + // and implement the added methods in customFsGuestModel. + FsGuestModel interface { + fsGuestModel + } + + customFsGuestModel struct { + *defaultFsGuestModel + } +) + +// NewFsGuestModel returns a model for the database table. +func NewFsGuestModel(conn sqlx.SqlConn) FsGuestModel { + return &customFsGuestModel{ + defaultFsGuestModel: newFsGuestModel(conn), + } +} diff --git a/model/fsguestmodel_gen.go b/model/fsguestmodel_gen.go new file mode 100755 index 00000000..71e7497c --- /dev/null +++ b/model/fsguestmodel_gen.go @@ -0,0 +1,92 @@ +// Code generated by goctl. DO NOT EDIT. + +package model + +import ( + "context" + "database/sql" + "fmt" + "strings" + + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" +) + +var ( + fsGuestFieldNames = builder.RawFieldNames(&FsGuest{}) + fsGuestRows = strings.Join(fsGuestFieldNames, ",") + fsGuestRowsExpectAutoSet = strings.Join(stringx.Remove(fsGuestFieldNames, "`guest_id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") + fsGuestRowsWithPlaceHolder = strings.Join(stringx.Remove(fsGuestFieldNames, "`guest_id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" +) + +type ( + fsGuestModel interface { + Insert(ctx context.Context, data *FsGuest) (sql.Result, error) + FindOne(ctx context.Context, guestId int64) (*FsGuest, error) + Update(ctx context.Context, data *FsGuest) error + Delete(ctx context.Context, guestId int64) error + } + + defaultFsGuestModel struct { + conn sqlx.SqlConn + table string + } + + FsGuest struct { + GuestId int64 `db:"guest_id"` // 游客ID + AuthKey string `db:"auth_key"` // jwt token + Status int64 `db:"status"` // 1正常 0不正常 + IsDel int64 `db:"is_del"` // 是否删除 1删除 + CreatedAt int64 `db:"created_at"` // 添加时间 + UpdatedAt int64 `db:"updated_at"` // 更新时间 + IsOpenRender int64 `db:"is_open_render"` // 是否打开个性化渲染(1:开启,0:关闭) + IsThousandFace int64 `db:"is_thousand_face"` // 是否已经存在千人千面(1:存在,0:不存在) + IsLowRendering int64 `db:"is_low_rendering"` // 是否开启低渲染模型渲染 + IsRemoveBg int64 `db:"is_remove_bg"` // 用户上传logo是否去除背景 + } +) + +func newFsGuestModel(conn sqlx.SqlConn) *defaultFsGuestModel { + return &defaultFsGuestModel{ + conn: conn, + table: "`fs_guest`", + } +} + +func (m *defaultFsGuestModel) Delete(ctx context.Context, guestId int64) error { + query := fmt.Sprintf("delete from %s where `guest_id` = ?", m.table) + _, err := m.conn.ExecCtx(ctx, query, guestId) + return err +} + +func (m *defaultFsGuestModel) FindOne(ctx context.Context, guestId int64) (*FsGuest, error) { + query := fmt.Sprintf("select %s from %s where `guest_id` = ? limit 1", fsGuestRows, m.table) + var resp FsGuest + err := m.conn.QueryRowCtx(ctx, &resp, query, guestId) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultFsGuestModel) Insert(ctx context.Context, data *FsGuest) (sql.Result, error) { + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?)", m.table, fsGuestRowsExpectAutoSet) + ret, err := m.conn.ExecCtx(ctx, query, data.AuthKey, data.Status, data.IsDel, data.IsOpenRender, data.IsThousandFace, data.IsLowRendering, data.IsRemoveBg) + return ret, err +} + +func (m *defaultFsGuestModel) Update(ctx context.Context, data *FsGuest) error { + query := fmt.Sprintf("update %s set %s where `guest_id` = ?", m.table, fsGuestRowsWithPlaceHolder) + _, err := m.conn.ExecCtx(ctx, query, data.AuthKey, data.Status, data.IsDel, data.IsOpenRender, data.IsThousandFace, data.IsLowRendering, data.IsRemoveBg, data.GuestId) + return err +} + +func (m *defaultFsGuestModel) tableName() string { + return m.table +} diff --git a/model/gmodel/fsguestmodel.go b/model/gmodel/fsguestmodel.go new file mode 100755 index 00000000..36bd6647 --- /dev/null +++ b/model/gmodel/fsguestmodel.go @@ -0,0 +1,14 @@ +package gmodel + +type FsGuest struct { + GuestId int64 `gorm:"" json:"guest_id"` // ID + AuthKey *string `gorm: json:"auth_key"` // jwt token + Status *int64 `gorm: json:"status"` // 1正常 0不正常 + IsDel *int64 `gorm: json:"is_del"` // 是否删除 1删除 + CreatedAt *int64 `gorm: json:"created_at"` // 添加时间 + UpdatedAt *int64 `gorm: json:"updated_at"` // 更新时间 + IsOpenRender *int64 `gorm: json:"is_open_render"` // 是否打开个性化渲染(1:开启,0:关闭) + IsThousandFace *int64 `gorm: json:"is_thousand_face"` // 是否已经存在千人千面(1:存在,0:不存在) + IsLowRendering *int64 `gorm: json:"is_low_rendering"` // 是否开启低渲染模型渲染 + IsRemoveBg *int64 `gorm: json:"is_remove_bg"` // 用户上传logo是否去除背景 +} diff --git a/model/gmodel_gen/fs_guest_gen.go b/model/gmodel_gen/fs_guest_gen.go new file mode 100644 index 00000000..9d8b796e --- /dev/null +++ b/model/gmodel_gen/fs_guest_gen.go @@ -0,0 +1,19 @@ +package model + +import "gorm.io/gorm" + +type FsGuest struct { + GuestId int64 `gorm:"primary_key" json:"guest_id"` // 游客ID + AuthKey *string `gorm:"" json:"auth_key"` // jwt token + Status *int64 `gorm:"" json:"status"` // 1正常 0不正常 + IsDel *int64 `gorm:"" json:"is_del"` // 是否删除 1删除 + CreatedAt *int64 `gorm:"" json:"created_at"` // 添加时间 + UpdatedAt *int64 `gorm:"" json:"updated_at"` // 更新时间 + IsOpenRender *int64 `gorm:"" json:"is_open_render"` // 是否打开个性化渲染(1:开启,0:关闭) + IsThousandFace *int64 `gorm:"" json:"is_thousand_face"` // 是否已经存在千人千面(1:存在,0:不存在) + IsLowRendering *int64 `gorm:"" json:"is_low_rendering"` // 是否开启低渲染模型渲染 + IsRemoveBg *int64 `gorm:"" json:"is_remove_bg"` // 用户上传logo是否去除背景 +} +type FsGuestModel struct{ db *gorm.DB } + +func NewFsGuestModel(db *gorm.DB) *FsGuestModel { return &FsGuestModel{db} } diff --git a/server/home-user-auth/internal/handler/acceptcookiehandler.go b/server/home-user-auth/internal/handler/acceptcookiehandler.go new file mode 100644 index 00000000..c4b168eb --- /dev/null +++ b/server/home-user-auth/internal/handler/acceptcookiehandler.go @@ -0,0 +1,78 @@ +package handler + +import ( + "errors" + "net/http" + + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/rest/httpx" + + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "fusenapi/server/home-user-auth/internal/logic" + "fusenapi/server/home-user-auth/internal/svc" + "fusenapi/server/home-user-auth/internal/types" +) + +func AcceptCookieHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} + } + + var req types.Request + // 如果端点有请求结构体,则使用httpx.Parse方法从HTTP请求体中解析请求数据 + if err := httpx.Parse(r, &req); err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 510, + Message: "parameter error", + }) + logx.Info(err) + return + } + // 创建一个业务逻辑层实例 + l := logic.NewAcceptCookieLogic(r.Context(), svcCtx) + resp := l.AcceptCookie(&req, userinfo) + // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; + if resp != nil { + httpx.OkJsonCtx(r.Context(), w, resp) + } else { + err := errors.New("server logic is error, resp must not be nil") + httpx.ErrorCtx(r.Context(), w, err) + logx.Error(err) + } + } +} diff --git a/server/home-user-auth/internal/handler/routes.go b/server/home-user-auth/internal/handler/routes.go index 3bc0f466..4a12513c 100644 --- a/server/home-user-auth/internal/handler/routes.go +++ b/server/home-user-auth/internal/handler/routes.go @@ -17,6 +17,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/user/login", Handler: UserLoginHandler(serverCtx), }, + { + Method: http.MethodPost, + Path: "/user/accept-cookie", + Handler: AcceptCookieHandler(serverCtx), + }, { Method: http.MethodGet, Path: "/user/fonts", @@ -42,17 +47,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/user/basic-info", Handler: UserBasicInfoHandler(serverCtx), }, - }, - ) - - server.AddRoutes( - []rest.Route{ { Method: http.MethodGet, Path: "/user/address-list", Handler: UserAddressListHandler(serverCtx), }, }, - rest.WithJwt(serverCtx.Config.Auth.AccessSecret), ) } diff --git a/server/home-user-auth/internal/handler/useraddresslisthandler.go b/server/home-user-auth/internal/handler/useraddresslisthandler.go index 5ecc5a96..271c3e24 100644 --- a/server/home-user-auth/internal/handler/useraddresslisthandler.go +++ b/server/home-user-auth/internal/handler/useraddresslisthandler.go @@ -15,15 +15,31 @@ import ( "fusenapi/server/home-user-auth/internal/types" ) -var wantJwt = true - func UserAddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - var userinfo *auth.UserInfo - var err error - if wantJwt { - userinfo, err = auth.ParseJwtToken(w, r, &svcCtx.Config.Auth.AccessSecret) + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 + claims, err := svcCtx.ParseJwtToken(r) + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 + }) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 + return + } + + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ Code: 401, @@ -32,6 +48,9 @@ func UserAddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { logx.Info("unauthorized:", err.Error()) return } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.Request @@ -48,7 +67,6 @@ func UserAddressListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserAddressListLogic(r.Context(), svcCtx) resp := l.UserAddressList(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/handler/userbasicinfohandler.go b/server/home-user-auth/internal/handler/userbasicinfohandler.go index 8a0245b8..b6aa5894 100644 --- a/server/home-user-auth/internal/handler/userbasicinfohandler.go +++ b/server/home-user-auth/internal/handler/userbasicinfohandler.go @@ -17,28 +17,40 @@ import ( func UserBasicInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.Request @@ -55,7 +67,6 @@ func UserBasicInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserBasicInfoLogic(r.Context(), svcCtx) resp := l.UserBasicInfo(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/handler/userfontshandler.go b/server/home-user-auth/internal/handler/userfontshandler.go index b7c1a6c2..e534f790 100644 --- a/server/home-user-auth/internal/handler/userfontshandler.go +++ b/server/home-user-auth/internal/handler/userfontshandler.go @@ -17,28 +17,40 @@ import ( func UserFontsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.Request @@ -55,7 +67,6 @@ func UserFontsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserFontsLogic(r.Context(), svcCtx) resp := l.UserFonts(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/handler/usergettypehandler.go b/server/home-user-auth/internal/handler/usergettypehandler.go index 21271e41..ccd49a20 100644 --- a/server/home-user-auth/internal/handler/usergettypehandler.go +++ b/server/home-user-auth/internal/handler/usergettypehandler.go @@ -17,28 +17,40 @@ import ( func UserGetTypeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.Request @@ -55,7 +67,6 @@ func UserGetTypeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserGetTypeLogic(r.Context(), svcCtx) resp := l.UserGetType(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/handler/usersavebasicinfohandler.go b/server/home-user-auth/internal/handler/usersavebasicinfohandler.go index a5894ff7..5e48dd1d 100644 --- a/server/home-user-auth/internal/handler/usersavebasicinfohandler.go +++ b/server/home-user-auth/internal/handler/usersavebasicinfohandler.go @@ -17,28 +17,40 @@ import ( func UserSaveBasicInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.RequestBasicInfoForm @@ -55,7 +67,6 @@ func UserSaveBasicInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserSaveBasicInfoLogic(r.Context(), svcCtx) resp := l.UserSaveBasicInfo(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/handler/userstatusconfighandler.go b/server/home-user-auth/internal/handler/userstatusconfighandler.go index 942b53f1..bc0d5ee6 100644 --- a/server/home-user-auth/internal/handler/userstatusconfighandler.go +++ b/server/home-user-auth/internal/handler/userstatusconfighandler.go @@ -17,28 +17,40 @@ import ( func UserStatusConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // 解析jwtToken + + var ( + // 定义错误变量 + err error + // 定义用户信息变量 + userinfo *auth.UserInfo + ) + // 解析JWT token,并对空用户进行判断 claims, err := svcCtx.ParseJwtToken(r) - // 如果解析出错,则返回未授权的JSON响应并记录错误消息 + // 如果解析JWT token出错,则返回未授权的JSON响应并记录错误消息 if err != nil { httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", + Code: 401, // 返回401状态码,表示未授权 + Message: "unauthorized", // 返回未授权信息 }) - logx.Info("unauthorized:", err.Error()) + logx.Info("unauthorized:", err.Error()) // 记录错误日志 return } - // 从Token里获取对应的信息 - userinfo, err := auth.GetUserInfoFormMapClaims(claims) - // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 - if err != nil { - httpx.OkJsonCtx(r.Context(), w, &basic.Response{ - Code: 401, - Message: "unauthorized", - }) - logx.Info("unauthorized:", err.Error()) - return + if claims != nil { + // 从token中获取对应的用户信息 + userinfo, err = auth.GetUserInfoFormMapClaims(claims) + // 如果获取用户信息出错,则返回未授权的JSON响应并记录错误消息 + if err != nil { + httpx.OkJsonCtx(r.Context(), w, &basic.Response{ + Code: 401, + Message: "unauthorized", + }) + logx.Info("unauthorized:", err.Error()) + return + } + } else { + // 如果claims为nil,则认为用户身份为白板用户 + userinfo = &auth.UserInfo{UserId: 0, GuestId: 0} } var req types.Request @@ -55,7 +67,6 @@ func UserStatusConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { l := logic.NewUserStatusConfigLogic(r.Context(), svcCtx) resp := l.UserStatusConfig(&req, userinfo) // 如果响应不为nil,则使用httpx.OkJsonCtx方法返回JSON响应; - // 否则,发送500内部服务器错误的JSON响应并记录错误消息logx.Error。 if resp != nil { httpx.OkJsonCtx(r.Context(), w, resp) } else { diff --git a/server/home-user-auth/internal/logic/acceptcookielogic.go b/server/home-user-auth/internal/logic/acceptcookielogic.go new file mode 100644 index 00000000..4e493ea0 --- /dev/null +++ b/server/home-user-auth/internal/logic/acceptcookielogic.go @@ -0,0 +1,38 @@ +package logic + +import ( + "fusenapi/utils/auth" + "fusenapi/utils/basic" + + "context" + + "fusenapi/server/home-user-auth/internal/svc" + "fusenapi/server/home-user-auth/internal/types" + + "github.com/zeromicro/go-zero/core/logx" +) + +type AcceptCookieLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewAcceptCookieLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AcceptCookieLogic { + return &AcceptCookieLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *AcceptCookieLogic) AcceptCookie(req *types.Request, userinfo *auth.UserInfo) (resp *basic.Response) { + // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) + // userinfo 传入值时, 一定不为null + idtyp := userinfo.GetIdType() + if idtyp == auth.IDTYPE_Guest { + return resp.SetStatus(basic.CodeDupGuestErr) + } + + return resp.SetStatus(basic.CodeOK) +} diff --git a/server/home-user-auth/internal/logic/userloginlogic.go b/server/home-user-auth/internal/logic/userloginlogic.go index 91dd916b..f877197d 100644 --- a/server/home-user-auth/internal/logic/userloginlogic.go +++ b/server/home-user-auth/internal/logic/userloginlogic.go @@ -48,7 +48,7 @@ func (l *UserLoginLogic) UserLogin(req *types.RequestUserLogin) (resp *basic.Res // 如果密码匹配,则生成 JWT Token。 nowSec := time.Now().Unix() - jwtToken, err = auth.GenerateJwtToken(l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire, nowSec, int(userModel.Id)) + jwtToken, err = auth.GenerateJwtToken(&l.svcCtx.Config.Auth.AccessSecret, l.svcCtx.Config.Auth.AccessExpire, nowSec, int64(userModel.Id), 0) // 如果生成 JWT Token 失败,则抛出错误并返回未认证的状态码。 if err != nil { diff --git a/server/home-user-auth/internal/svc/servicecontext.go b/server/home-user-auth/internal/svc/servicecontext.go index 8c26ba0b..2d97fe86 100644 --- a/server/home-user-auth/internal/svc/servicecontext.go +++ b/server/home-user-auth/internal/svc/servicecontext.go @@ -24,8 +24,8 @@ func NewServiceContext(c config.Config) *ServiceContext { func (svcCxt *ServiceContext) ParseJwtToken(r *http.Request) (jwt.MapClaims, error) { AuthKey := r.Header.Get("Authorization") - if len(AuthKey) <= 50 { - return nil, errors.New(fmt.Sprint("Error parsing token, len:", len(AuthKey))) + if AuthKey == "" { + return nil, nil } token, err := jwt.Parse(AuthKey, func(token *jwt.Token) (interface{}, error) { diff --git a/server_api/home-user-auth.api b/server_api/home-user-auth.api index b038ef9b..5f4a425c 100644 --- a/server_api/home-user-auth.api +++ b/server_api/home-user-auth.api @@ -18,6 +18,9 @@ service home-user-auth { @handler UserLoginHandler post /user/login(RequestUserLogin) returns (response); + @handler AcceptCookieHandler + post /user/accept-cookie(request) returns (response); + @handler UserFontsHandler get /user/fonts(request) returns (response); @@ -33,17 +36,9 @@ service home-user-auth { @handler UserBasicInfoHandler get /user/basic-info(request) returns (response); - // @handler UserAddressListHandler - // get /user/address-list(request) returns (response); - -} - -@server( - jwt: Auth -) -service home-user-auth { @handler UserAddressListHandler get /user/address-list(request) returns (response); + } type RequestBasicInfoForm { diff --git a/utils/auth/user.go b/utils/auth/user.go index 63c08bef..ef04cd9f 100644 --- a/utils/auth/user.go +++ b/utils/auth/user.go @@ -8,17 +8,41 @@ import ( "net/http" "github.com/golang-jwt/jwt" - "github.com/google/uuid" "github.com/zeromicro/go-zero/core/logx" ) +type IDTYPE int + +const ( + // 白板用户, 以观众身份命名, 没有接收Cookie, 没有拿到guest_id的用户 + IDTYPE_Onlooker IDTYPE = 0 + // 登录用户 + IDTYPE_User IDTYPE = 1 + // 游客 接收授权拿到guest_id的用户 + IDTYPE_Guest IDTYPE = 2 +) + type UserInfo struct { - UserId int64 `json:"userid"` + UserId int64 `json:"user_id"` + GuestId int64 `json:"guest_id"` +} + +// GetIdType 用户确认用户身份类型 +func (info *UserInfo) GetIdType() IDTYPE { + if info.UserId != 0 { + return IDTYPE_User + } + + if info.GuestId != 0 { + return IDTYPE_Guest + } + + return IDTYPE_Onlooker } // 获取登录信息 func GetUserInfoFormCtx(ctx context.Context) UserInfo { - uid, err := ctx.Value("userid").(json.Number).Int64() + uid, err := ctx.Value("user_id").(json.Number).Int64() if err != nil { logx.Error("parse uid form context err:", err.Error()) return UserInfo{} @@ -28,43 +52,60 @@ func GetUserInfoFormCtx(ctx context.Context) UserInfo { // 获取登录信息 func GetUserInfoFormMapClaims(claims jwt.MapClaims) (*UserInfo, error) { - if userid, ok := claims["userid"]; ok { + userinfo := &UserInfo{} + if userid, ok := claims["user_id"]; ok { uid, ok := userid.(float64) if !ok { err := errors.New(fmt.Sprint("parse uid form context err:", userid)) logx.Error("parse uid form context err:", err) return nil, err } - - return &UserInfo{UserId: int64(uid)}, nil + userinfo.UserId = int64(uid) } else { err := errors.New(`userid not in claims`) logx.Error(`userid not in claims`) return nil, err } + + if guestid, ok := claims["guest_id"]; ok { + gid, ok := guestid.(float64) + if !ok { + err := errors.New(fmt.Sprint("parse guestid form context err:", guestid)) + logx.Error("parse guestid form context err:", err) + return nil, err + } + userinfo.GuestId = int64(gid) + } else { + err := errors.New(`userid not in claims`) + logx.Error(`userid not in claims`) + return nil, err + } + + return userinfo, nil } -func GenerateJwtToken(accessSecret string, accessExpire, nowSec int64, userid int) (string, error) { +func GenerateJwtToken(accessSecret *string, accessExpire, nowSec int64, userid int64, guestid int64) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec - claims["userid"] = userid - if userid == 0 { - u, err := uuid.NewUUID() - if err != nil { - logx.Error(err) - return "", err - } - claims["guestid"] = u.String() // TODO: 未完成 + + if userid == 0 && guestid == 0 { + err := errors.New("userid and guestid cannot be 0 at the same time") + logx.Error(err) + return "", err + } + claims["user_id"] = userid + claims["guest_id"] = guestid + token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims - return token.SignedString([]byte(accessSecret)) + return token.SignedString([]byte(*accessSecret)) } func ParseJwtToken(w http.ResponseWriter, r *http.Request, AccessSecret *string) (*UserInfo, error) { // 解析jwtToken - claims, err := getJwtClaims(r, AccessSecret) + claims, err := getJwtClaimsFromRequest(r, AccessSecret) // 如果解析出错,则返回未授权的JSON响应并记录错误消息 if err != nil { // httpx.OkJsonCtx(r.Context(), w, &basic.Response{ @@ -89,12 +130,17 @@ func ParseJwtToken(w http.ResponseWriter, r *http.Request, AccessSecret *string) return userinfo, err } -func getJwtClaims(r *http.Request, AccessSecret *string) (jwt.MapClaims, error) { +func getJwtClaimsFromRequest(r *http.Request, AccessSecret *string) (jwt.MapClaims, error) { AuthKey := r.Header.Get("Authorization") if len(AuthKey) <= 50 { return nil, errors.New(fmt.Sprint("Error parsing token, len:", len(AuthKey))) } + return getJwtClaims(AuthKey, AccessSecret) +} + +func getJwtClaims(AuthKey string, AccessSecret *string) (jwt.MapClaims, error) { + token, err := jwt.Parse(AuthKey, func(token *jwt.Token) (interface{}, error) { // 检查签名方法是否为 HS256 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { diff --git a/utils/auth/user_test.go b/utils/auth/user_test.go new file mode 100644 index 00000000..be61e5d9 --- /dev/null +++ b/utils/auth/user_test.go @@ -0,0 +1,30 @@ +package auth + +import ( + "testing" + "time" +) + +// TestGenJwt 测试jwt序列化 +func TestGenJwt(t *testing.T) { + now := time.Now().Unix() + secret := "fusen123" + a, err := GenerateJwtToken(&secret, 3600, now, 123, 1234) + if err != nil { + t.Error(err) + } + // log.Println(a) + + claims, err := getJwtClaims(a, &secret) + if err != nil { + t.Error(err) + } + userinfo, err := GetUserInfoFormMapClaims(claims) + if err != nil { + t.Error(err) + } + if userinfo.UserId != 123 || userinfo.GuestId != 1234 { + t.Error(userinfo) + } + // log.Println(claims) +} diff --git a/utils/basic/basic.go b/utils/basic/basic.go index c5bcc5b2..3671ddcb 100644 --- a/utils/basic/basic.go +++ b/utils/basic/basic.go @@ -13,7 +13,8 @@ var ( CodeServiceErr = &StatusResponse{510, "server logic error"} // server logic 错误 CodeUnAuth = &StatusResponse{401, "unauthorized"} // 未授权 - CodeUpdateErr = &StatusResponse{5000, "update database error"} // update database logic 错误 + CodeUpdateErr = &StatusResponse{5000, "update database error"} // update database logic 错误 + CodeDupGuestErr = &StatusResponse{5001, "the user is already a guest user and does not need to apply again"} // 用户已经是guest用户不需要重复申请 错误 ) type Response struct {