Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/admin/main/passport/cmd:all-srcs",
"//app/admin/main/passport/conf:all-srcs",
"//app/admin/main/passport/dao:all-srcs",
"//app/admin/main/passport/http:all-srcs",
"//app/admin/main/passport/model:all-srcs",
"//app/admin/main/passport/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,13 @@
#### v1.2.1
1. 修复/userBindLog没有校验权限bug
#### v1.2.0
1. 添加"action"字段搜索
#### v1.1.0
1. fix "/x/admin/passport/userBindLog"
2. 1. fix "/x/admin/passport/user_bind_log/decrypt"
#### v1.0.0
1. 添加行为日志数据解析接口

View File

@@ -0,0 +1,9 @@
# Owner
wanghuan01
zhoujiahui
# Author
gezhangyuan
# Reviewer
wanghuan01

View File

@@ -0,0 +1,15 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- gezhangyuan
- wanghuan01
- zhoujiahui
labels:
- admin
- admin/main/passport
- main
options:
no_parent_owners: true
reviewers:
- gezhangyuan
- wanghuan01

View File

@@ -0,0 +1,12 @@
# passport-admin
# 项目简介
1.
# 编译环境
# 依赖包
# 编译执行

View File

@@ -0,0 +1,42 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["passport-admin.toml"],
importpath = "go-common/app/admin/main/passport/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/passport/conf:go_default_library",
"//app/admin/main/passport/http:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,40 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"go-common/app/admin/main/passport/conf"
"go-common/app/admin/main/passport/http"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
log.Info("passport-admin start")
trace.Init(conf.Conf.Tracer)
defer trace.Close()
http.Init(conf.Conf)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("passport-admin get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("passport-admin exit")
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,72 @@
# This is a TOML document. Boom
version = "1.0.0"
user = "nobody"
pid = "/tmp/passport-admin.pid"
dir = "./"
[encode]
salt = ""
aesKey = "0123456789abcdef"
[elastic]
#host = "http://uat-manager.bilibili.co"
host = "http://127.0.0.1:8080"
[elastic.HTTPClient]
key = "3c4e41f926e51656"
secret = "26a2095b60c24154521d24ae62b885bb"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[elastic.HTTPClient.breaker]
window ="3s"
sleep ="100ms"
bucket = 10
ratio = 0.5
request = 100
[permit]
managerHost = "http://uat-manager.bilibili.co"
dashboardHost = "http://dashboard-mng.bilibili.co"
dashboardCaller = "manager-go"
[auth.DsHTTPClient]
key = "manager-go"
secret = "949bbb2dd3178252638c2407578bc7ad"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.DsHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.MaHTTPClient]
key = "f6433799dbd88751"
secret = "36f8ddb1806207fe07013ab6a77a3935"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
[auth.MaHTTPClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[auth.session]
sessionIDLength = 32
cookieLifeTime = 1800
cookieName = "mng-go"
domain = ".bilibili.co"
[auth.session.Memcache]
name = "go-business/auth"
proto = "tcp"
addr = "172.18.33.61:11232"
active = 5
idle = 5
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"

View File

@@ -0,0 +1,38 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/admin/main/passport/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/conf:go_default_library",
"//library/database/elastic:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/trace:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,92 @@
package conf
import (
"errors"
"flag"
"go-common/library/conf"
"go-common/library/database/elastic"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/trace"
"github.com/BurntSushi/toml"
)
var (
confPath string
client *conf.Client
// Conf config
Conf = &Config{}
)
// Config .
type Config struct {
Log *log.Config
BM *bm.ServerConfig
Verify *verify.Config
Tracer *trace.Config
Encode *Encode
// elastic config
Elastic *elastic.Config
Permit *permit.Config
}
// Encode encode
type Encode struct {
AesKey string
Salt string
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init conf
func Init() error {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,32 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/admin/main/passport/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/passport/conf:go_default_library",
"//library/database/elastic:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,35 @@
package dao
import (
"context"
"go-common/library/database/elastic"
"go-common/app/admin/main/passport/conf"
)
// Dao dao
type Dao struct {
c *conf.Config
// elastic client
EsCli *elastic.Elastic
}
// New init mysql db
func New(c *conf.Config) (dao *Dao) {
dao = &Dao{
c: c,
// elastic client
EsCli: elastic.NewElastic(c.Elastic),
}
return
}
// Close close the resource.
func (d *Dao) Close() {
}
// Ping dao ping
func (d *Dao) Ping(c context.Context) error {
return nil
}

View File

@@ -0,0 +1,39 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"user_act_log.go",
],
importpath = "go-common/app/admin/main/passport/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/passport/conf:go_default_library",
"//app/admin/main/passport/model:go_default_library",
"//app/admin/main/passport/service:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,49 @@
package http
import (
"net/http"
"go-common/app/admin/main/passport/conf"
"go-common/app/admin/main/passport/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/permit"
)
var (
srv *service.Service
permitSvr *permit.Permit
)
// Init init
func Init(c *conf.Config) {
srv = service.New(c)
engine := bm.DefaultServer(c.BM)
permitSvr = permit.New(c.Permit)
router(engine)
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
func router(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
g := e.Group("/x/admin/passport")
{
g.GET("/userBindLog", permitSvr.Permit("LOG_USER_CONTACT_CHANGE"), userBindLog)
g.GET("/user_bind_log/decrypt", decryptBindLog)
}
}
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,25 @@
package http
import (
"go-common/app/admin/main/passport/model"
bm "go-common/library/net/http/blademaster"
)
// @params UserBindLogReq
// @router get /x/admin/passport/userBindLog
// @response UserBindLogRes
func userBindLog(c *bm.Context) {
userActLogReq := new(model.UserBindLogReq)
c.Bind(userActLogReq)
c.JSON(srv.UserBindLog(c, userActLogReq))
}
// @params DecryptBindLogParam
// @router get /x/admin/passport/user_bind_log/decrypt
// @response map[]string
func decryptBindLog(c *bm.Context) {
param := new(model.DecryptBindLogParam)
c.Bind(param)
c.JSON(srv.DecryptBindLog(c, param))
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["model.go"],
importpath = "go-common/app/admin/main/passport/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,54 @@
package model
// DecryptBindLogParam DecryptBindLogParam
type DecryptBindLogParam struct {
EncryptText []string `form:"text,split" validate:"min=1"` // 密文字段,','分割
}
// UserBindLogReq UserBindLogReq
type UserBindLogReq struct {
// Action value : telBindLog or emailBindLog
Action string `form:"action"`
Mid int64 `form:"mid"`
//Query search tel or email
Query string `form:"query"`
Page int `form:"page"`
Size int `form:"size"`
From int64 `form:"from"`
To int64 `form:"to"`
}
// EsRes EsRes
type EsRes struct {
Page Page `json:"page"`
Result []*UserActLogEs `json:"result"`
}
// Page Page
type Page struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
}
// UserActLogEs UserActLogEs
type UserActLogEs struct {
Mid int64 `json:"mid"`
Str0 string `json:"str_0"`
ExtraData string `json:"extra_data"`
CTime string `json:"ctime"`
}
// UserBindLogRes UserBindLogRes
type UserBindLogRes struct {
Page Page `json:"page"`
Result []*UserBindLog `json:"result"`
}
// UserBindLog UserBindLog
type UserBindLog struct {
Mid int64 `json:"mid"`
Phone string `json:"phone"`
EMail string `json:"email"`
Time string `json:"time"`
}

View File

@@ -0,0 +1,53 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"aes.go",
"service.go",
"user_act_log.go",
],
importpath = "go-common/app/admin/main/passport/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/passport/conf:go_default_library",
"//app/admin/main/passport/dao:go_default_library",
"//app/admin/main/passport/model:go_default_library",
"//library/database/elastic:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["user_act_log_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/passport/conf:go_default_library",
"//app/admin/main/passport/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,63 @@
package service
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"errors"
)
//func pad(src []byte) []byte {
// padding := aes.BlockSize - len(src)%aes.BlockSize
// padText := bytes.Repeat([]byte{byte(padding)}, padding)
// return append(src, padText...)
//}
func unpad(src []byte) ([]byte, error) {
length := len(src)
unpadding := int(src[length-1])
if unpadding > length {
return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
}
return src[:(length - unpadding)], nil
}
//func (s *Service) encrypt(text string) (string, error) {
// msg := pad([]byte(text))
// cipherText := make([]byte, aes.BlockSize+len(msg))
// iv := cipherText[:aes.BlockSize]
// if _, err := io.ReadFull(rand.Reader, iv); err != nil {
// return "", err
// }
//
// cfb := cipher.NewCFBEncrypter(s.AESBlock, iv)
// cfb.XORKeyStream(cipherText[aes.BlockSize:], []byte(msg))
// finalMsg := base64.URLEncoding.EncodeToString(cipherText)
// return finalMsg, nil
//}
func (s *Service) decrypt(text string) (string, error) {
decodedMsg, err := base64.URLEncoding.DecodeString(text)
if err != nil {
return "", err
}
if (len(decodedMsg) % aes.BlockSize) != 0 {
return "", errors.New("blocksize must be multipe of decoded message length")
}
iv := decodedMsg[:aes.BlockSize]
msg := decodedMsg[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(s.AESBlock, iv)
cfb.XORKeyStream(msg, msg)
unpadMsg, err := unpad(msg)
if err != nil {
return "", err
}
return string(unpadMsg), nil
}

View File

@@ -0,0 +1,39 @@
package service
import (
"context"
"crypto/aes"
"crypto/cipher"
"go-common/app/admin/main/passport/conf"
"go-common/app/admin/main/passport/dao"
)
// Service struct
type Service struct {
c *conf.Config
dao *dao.Dao
AESBlock cipher.Block
hashSalt []byte
}
// New init
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
hashSalt: []byte(c.Encode.Salt),
}
s.AESBlock, _ = aes.NewCipher([]byte(c.Encode.AesKey))
return s
}
// Ping Service
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// Close Service
func (s *Service) Close() {
s.dao.Close()
}

View File

@@ -0,0 +1,107 @@
package service
import (
"context"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"strconv"
"time"
"go-common/app/admin/main/passport/model"
"go-common/library/database/elastic"
"go-common/library/log"
)
type userLogsExtra struct {
EncryptTel string `json:"tel"`
EncryptEmail string `json:"email"`
}
// UserBindLog User bind log
func (s *Service) UserBindLog(c context.Context, userActLogReq *model.UserBindLogReq) (res *model.UserBindLogRes, err error) {
e := s.dao.EsCli
nowYear := time.Now().Year()
index1 := "log_user_action_54_" + strconv.Itoa(nowYear)
index2 := "log_user_action_54_" + strconv.Itoa(nowYear-1)
r := e.NewRequest("log_user_action").Fields("mid", "str_0", "extra_data", "ctime").Index(index1, index2)
r.Order("ctime", elastic.OrderDesc).Order("mid", elastic.OrderDesc).Pn(userActLogReq.Page).Ps(userActLogReq.Size)
if userActLogReq.Mid != 0 {
r.WhereEq("mid", userActLogReq.Mid)
}
if userActLogReq.Query != "" {
hash := sha1.New()
hash.Write([]byte(userActLogReq.Query))
telHash := base64.StdEncoding.EncodeToString(hash.Sum(s.hashSalt))
r.WhereEq("str_0", telHash)
}
if userActLogReq.Action != "" {
r.WhereEq("action", userActLogReq.Action)
}
if userActLogReq.From != 0 && userActLogReq.To != 0 {
ftm := time.Unix(userActLogReq.From, 0)
sf := ftm.Format("2006-01-02 15:04:05")
ttm := time.Unix(userActLogReq.To, 0)
tf := ttm.Format("2006-01-02 15:04:05")
r.WhereRange("ctime", sf, tf, elastic.RangeScopeLoRo)
}
esres := new(model.EsRes)
if err = r.Scan(context.Background(), &esres); err != nil {
log.Error("userActLogs search error(%v)", err)
}
var users = make([]*model.UserBindLog, 0)
for _, value := range esres.Result {
var email, tel string
//var model.UserBindLog
userLogExtra := userLogsExtra{}
err = json.Unmarshal([]byte(value.ExtraData), &userLogExtra)
if err != nil {
log.Error("cannot convert json(%s) to struct,err(%+v) ", value.ExtraData, err)
continue
}
if userLogExtra.EncryptEmail != "" {
email, err = s.decrypt(userLogExtra.EncryptEmail)
if err != nil {
log.Error("EncryptEmail decode err(%v)", err)
continue
}
}
if userLogExtra.EncryptTel != "" {
tel, err = s.decrypt(userLogExtra.EncryptTel)
if err != nil {
log.Error("EncryptTel decode err(%v)", err)
continue
}
}
ulr := model.UserBindLog{Mid: value.Mid, EMail: email, Phone: tel, Time: value.CTime}
users = append(users, &ulr)
}
res = &model.UserBindLogRes{Page: esres.Page, Result: users}
return
}
// DecryptBindLog decrypt bind log
func (s *Service) DecryptBindLog(c context.Context, reqParams *model.DecryptBindLogParam) (res map[string]string, err error) {
if len(reqParams.EncryptText) == 0 {
return make(map[string]string), nil
}
res = make(map[string]string, len(reqParams.EncryptText))
for _, v := range reqParams.EncryptText {
var tel string
if tel, err = s.decrypt(v); err != nil {
return
}
res[v] = tel
}
return
}

View File

@@ -0,0 +1,26 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/passport/conf"
"go-common/app/admin/main/passport/model"
"github.com/smartystreets/goconvey/convey"
)
func TestService_DecryptBindLog(t *testing.T) {
config := &conf.Config{
Encode: &conf.Encode{
AesKey: "0123456789abcdef",
Salt: "",
},
}
s := New(config)
convey.Convey("", t, func() {
res, err := s.DecryptBindLog(context.Background(), &model.DecryptBindLogParam{EncryptText: []string{"IsjRu7dmHBY8l7bGf6O3rgDegFvh3cVTgWkf2Bn87Oc="}})
convey.So(err, convey.ShouldBeNil)
convey.So(res["IsjRu7dmHBY8l7bGf6O3rgDegFvh3cVTgWkf2Bn87Oc="], convey.ShouldEqual, "19921218988")
})
}

View File

@@ -0,0 +1,145 @@
{
"swagger": "2.0",
"info": {
"title": "go-common api",
"description": "api",
"version": "1.0",
"contact": {
"email": "lintanghui@bilibili.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
},
"paths": {
"/x/admin/passport/userBindLog": {
"get": {
"operationId": "/x/admin/passport/userBindLog",
"parameters": [
{
"in": "query",
"name": "query",
"type": "string"
},
{
"in": "query",
"name": "page",
"type": "integer",
"format": "int64"
},
{
"in": "query",
"name": "size",
"type": "integer",
"format": "int64"
},
{
"in": "query",
"name": "from",
"type": "integer",
"format": "int64"
},
{
"in": "query",
"name": "to",
"type": "integer",
"format": "int64"
},
{
"in": "query",
"name": "mid",
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "服务成功响应内容",
"schema": {
"type": "object",
"properties": {
"code": {
"description": "错误码描述",
"type": "integer"
},
"data": {
"$ref": "#/definitions/UserBindLogRes",
"type": "object"
},
"message": {
"description": "错误码文本描述",
"type": "string"
},
"ttl": {
"description": "客户端限速时间",
"type": "integer",
"format": "int64"
}
}
}
}
}
}
}
},
"definitions": {
"Page": {
"title": "Page",
"description": "Page Page",
"type": "object",
"properties": {
"Num": {
"type": "integer",
"format": "int64"
},
"Size": {
"type": "integer",
"format": "int64"
},
"Total": {
"type": "integer",
"format": "int64"
}
}
},
"UserBindLog": {
"title": "UserBindLog",
"description": "UserBindLog UserBindLog",
"type": "object",
"properties": {
"EMail": {
"type": "string"
},
"Mid": {
"type": "integer",
"format": "int64"
},
"Phone": {
"type": "string"
},
"Time": {
"type": "string"
}
}
},
"UserBindLogRes": {
"title": "UserBindLogRes",
"description": "UserBindLogRes UserBindLogRes",
"type": "object",
"properties": {
"Page": {
"$ref": "#/definitions/Page",
"type": "object"
},
"Result": {
"type": "array",
"items": {
"$ref": "#/definitions/UserBindLog",
"type": "object"
}
}
}
}
}
}