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,23 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/identify/api/grpc:all-srcs",
"//app/service/main/identify/cmd:all-srcs",
"//app/service/main/identify/conf:all-srcs",
"//app/service/main/identify/dao:all-srcs",
"//app/service/main/identify/model:all-srcs",
"//app/service/main/identify/server/grpc:all-srcs",
"//app/service/main/identify/server/http:all-srcs",
"//app/service/main/identify/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,82 @@
### identify-service
#### Version 1.17.0
> 1. fix intranet ip
#### Version 1.16.0
> 1. use Add instead of Set for login cache
#### Version 1.15.1
> 1. use Add instead of Set for login cache
#### Version 1.15.0
> 1. login log add 'buvid', 'ip' fields
#### Version 1.14.0
> 1. empty identify cache expires: 30s -> 1d
#### Version 1.13.3
> 1. fix nil check
#### Version 1.13.2
> 1. fix remote ip
> 2. fix cookie expires check
#### Version 1.13.1
> 1. add ut
#### Version 1.12.0
> 1. fix grpc cookie unescape
> 2. del cookie dedeuserid check
> 3. del GetCookieInfo ssda param
#### Version 1.11.0
> 1. delete identify gorpc
#### Version 1.10.0
> 1. defined pb struct String method
> 2. add login cache expires config
#### Version 1.9.0
> 1. change remote ip
#### Version 1.8.2
> 1. fix login cache set
#### Version 1.8.1
> 1. fix json omitempty
#### Version 1.8.0
> 1. add login log
#### Version 1.7.0
> 1. use verify instead of identify
#### Version 1.6.1
> 1. fix gRPC interceptor
#### Version 1.6.0
> 1. add mid log
#### Version 1.5.1
> 1.gRPC 方法名统一
> 2.http delCache method no-op
> 3.http ping no-op
#### Version 1.5.0
> 1.gRPC 支持
#### Version 1.4.0
> 1.use bm
#### Version 1.3.0
> 1.move to main/identify
#### Version 1.2.0
> 1.add RPC
#### Version 1.1.0
> 1.支持purge 缓存
#### Version 1.0.0
> 1.passport二级缓存服务

View File

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

View File

@@ -0,0 +1,14 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- wucongyou
labels:
- main
- service
- service/main/identify
options:
no_parent_owners: true
reviewers:
- wanghuan01
- wucongyou

View File

@@ -0,0 +1,13 @@
#### identify-service
##### 项目简介
> 1.passport二级缓存服务
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 特别说明
> 1.model目录可能会被其他项目引用请谨慎请改并通知各方。

View File

@@ -0,0 +1,66 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
proto_library(
name = "v1_proto",
srcs = ["api.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "v1_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_grpc"],
importpath = "go-common/app/service/main/identify/api/grpc",
proto = ":v1_proto",
tags = ["manual"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"client.go",
"string.go",
],
embed = [":v1_go_proto"],
importpath = "go-common/app/service/main/identify/api/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/net/rpc/warden:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_x_net//context: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 = ["string_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
// +bili:type=service
// Code generated by warden.
syntax = "proto3";
package passport.service.identify.v1;
option go_package = "v1";
option (gogoproto.goproto_stringer_all) = false;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// CookieReq request param for rpc CookieInfo
message GetCookieInfoReq {
// all user cookie of HTTP request
// example: 'SESSDATA=DEE4597D836A5A9DA29DFC1AB1EFFDEB;sid=exampleSID'
string cookie = 1;
}
// CookieReply reply val for rpc CookieInfo
message GetCookieInfoReply {
// 用户是否登录
bool is_login = 1 [(gogoproto.jsontag) = "is_login"];
// user mid
int64 mid = 2 [(gogoproto.jsontag) = "mid"];
// cookie csrf
// when token reqest this field is empty
string csrf = 3 [(gogoproto.jsontag) = "csrfToken"];
// expire time(unix timestamp)
int32 expires = 4 [(gogoproto.jsontag) = "expires"];
}
// TokenReq request param for rpc TokenInfo
message GetTokenInfoReq {
// user access token
string token = 1 [(gogoproto.moretags) = "form:\"access_key\" validate:\"required\""];
// buvid
string buvid = 2 [(gogoproto.moretags) = "form:\"buvid\""];
}
// TokenReply reply val for rpc TokenInfo
message GetTokenInfoReply {
// 用户是否登录
bool is_login = 1 [(gogoproto.jsontag) = "is_login"];
// user mid
int64 mid = 2 [(gogoproto.jsontag) = "mid"];
// cookie csrf
// when token reqest this field is empty
string csrf = 3 [(gogoproto.jsontag) = "csrfToken"];
// expire time(unix timestamp)
int32 expires = 4 [(gogoproto.jsontag) = "expires"];
}
service Identify {
// CookieInfo identify info by cookie.
rpc GetCookieInfo (GetCookieInfoReq) returns (GetCookieInfoReply);
// TokenInfo identify info by token.
rpc GetTokenInfo (GetTokenInfoReq) returns (GetTokenInfoReply);
}

View File

@@ -0,0 +1,34 @@
// Package v1 .
// NOTE: need registery discovery resovler into grpc before use this client
/*
import (
"go-common/library/naming/discovery"
"go-common/library/net/rpc/warden/resolver"
)
func main() {
resolver.Register(discovery.New(nil))
}
*/
package v1
import (
"context"
"google.golang.org/grpc"
"go-common/library/net/rpc/warden"
)
// AppID unique app id for service discovery
const AppID = "passport.service.identify"
// NewClient new identify grpc client
func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (IdentifyClient, error) {
client := warden.NewClient(cfg, opts...)
conn, err := client.Dial(context.Background(), "discovery://default/"+AppID)
if err != nil {
return nil, err
}
return NewIdentifyClient(conn), nil
}

View File

@@ -0,0 +1,25 @@
package v1
import (
"github.com/gogo/protobuf/proto"
)
// String GetCookieInfoReq string
func (m *GetCookieInfoReq) String() string {
return ""
}
// String GetCookieInfoReply string
func (m *GetCookieInfoReply) String() string {
return proto.MarshalTextString(m)
}
// String GetTokenInfoReq string
func (m *GetTokenInfoReq) String() string {
return proto.MarshalTextString(m)
}
// String GetTokenInfoReply string
func (m *GetTokenInfoReply) String() string {
return proto.MarshalTextString(m)
}

View File

@@ -0,0 +1,13 @@
package v1
import (
"fmt"
"testing"
)
func TestGetCookieInfoReply_String(t *testing.T) {
m := GetCookieInfoReq{
Cookie: "==000123000==",
}
fmt.Println(fmt.Sprintf("%v", m))
}

View File

@@ -0,0 +1,44 @@
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 = ["identify-service-test.toml"],
importpath = "go-common/app/service/main/identify/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/server/grpc:go_default_library",
"//app/service/main/identify/server/http:go_default_library",
"//app/service/main/identify/service: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,83 @@
# This is a TOML document. Boom.
[Identify]
authHost = "http://passport.bilibili.co"
# sync whith userlog databus
LoginLogConsumerSize = 10
IntranetCIDR = ["172.16.0.0/12", "10.0.0.0/8", "192.168.0.0/16"]
[rpcServer2]
[[rpcServer2.servers]]
proto = "tcp"
addr = "0.0.0.0:7379"
weight = 10
[rpcServer2.zookeeper]
root = "/microservice/identify-service/"
addrs = ["172.18.33.172:2181"]
timeout = "1s"
[bm]
addr = "0.0.0.0:7371"
timeout = "1s"
[HTTPClient]
dial = "50ms"
timeout = "200ms"
keepAlive = "60s"
key = "f265dcfa28272742"
secret = "437facc22dc8698b5544669bcc12348d"
[HTTPClient.breaker]
window ="1s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[Memcache]
name = "identify-service"
proto = "tcp"
addr = "172.18.33.61:11234"
idle = 1000
active = 1000
dialTimeout = "10s"
readTimeout = "10s"
writeTimeout = "10s"
idleTimeout = "30s"
settingExpire = "720h"
reportExpire = "720h"
[wardenServer]
addr = "0.0.0.0:6077"
timeout = "1s"
[liveZK]
addrs = ["172.16.33.249:2189"]
timeout = "1s"
[databus.userLog]
key = "2511663d546f1413"
secret = "cde3b480836cc76df3d635470f991caa"
group = "LogUserAction-MainSearch-P"
topic = "LogUserAction-T"
action = "pub"
buffer = 10240
name = "log-user-action/log-sub"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 10
active = 10
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[MemcacheLoginLog]
name = "identify-service"
proto = "tcp"
addr = "172.18.33.61:11234"
idle = 1000
active = 1000
dialTimeout = "10s"
readTimeout = "10s"
writeTimeout = "10s"
idleTimeout = "30s"
settingExpire = "720h"
reportExpire = "720h"

View File

@@ -0,0 +1,67 @@
package main
import (
"context"
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/identify/conf"
"go-common/app/service/main/identify/server/grpc"
"go-common/app/service/main/identify/server/http"
"go-common/app/service/main/identify/service"
"go-common/library/log"
// "go-common/library/net/rpc/warden/resolver/livezk"
"go-common/library/net/trace"
)
const (
// discoveryID = "passport.service.identify"
)
func main() {
flag.Parse()
// init conf,log,trace,stat,perf.
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
// service init
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
// init warden server
ws := grpc.New(conf.Conf.WardenServer, svr)
// 先主站内部和chenzhihui测试可用再对外提供
// cancel, err := livezk.Register(conf.Conf.LiveZK, conf.Conf.WardenServer.Addr, discoveryID)
// if err != nil {
// panic(err)
// }
// signal handler
log.Info("identify-service start")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("identify-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGSTOP, syscall.SIGINT:
// cancel()
ws.Shutdown(context.Background())
time.Sleep(time.Second * 2)
svr.Close()
log.Info("identify-service exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,40 @@
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/service/main/identify/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/log:go_default_library",
"//library/naming/livezk:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus: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,115 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/log"
"go-common/library/naming/livezk"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// Config struct of conf.
type Config struct {
// log
Xlog *log.Config
//Tracer *conf.Tracer
Tracer *trace.Config
// VerifyConfig
VerifyConfig *verify.Config
// BM
BM *bm.ServerConfig
// http client
HTTPClient *bm.ClientConfig
// memcache
Memcache *memcache.Config
// MemcacheLoginLog
MemcacheLoginLog *memcache.Config
// grpc server
WardenServer *warden.ServerConfig
// live zookeeper
LiveZK *livezk.Zookeeper
// IdentifyConfig
Identify *IdentifyConfig
// DataBus config
DataBus *DataBus
}
// IdentifyConfig identify config
type IdentifyConfig struct {
AuthHost string
// LoginLogConsumerSize goroutine size
LoginLogConsumerSize int
// LoginCacheExpires login check cache expires
LoginCacheExpires int32
// IntranetCIDR
IntranetCIDR []string
}
// DataBus data bus config
type DataBus struct {
UserLog *databus.Config
}
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 event")
}
}()
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
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init int config
func Init() error {
if confPath != "" {
return local()
}
return remote()
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"memcache_test.go",
"passport_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"memcache.go",
"passport.go",
],
importpath = "go-common/app/service/main/identify/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/stat/prom: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,73 @@
package dao
import (
"context"
"go-common/app/service/main/identify/conf"
"go-common/library/cache/memcache"
bm "go-common/library/net/http/blademaster"
"go-common/library/stat/prom"
)
const (
_tokenURI = "/intranet/auth/tokenInfo"
_cookieURI = "/intranet/auth/cookieInfo"
)
var (
errorsCount = prom.BusinessErrCount
cachedCount = prom.CacheHit
missedCount = prom.CacheMiss
)
// PromError prom error
func PromError(name string) {
errorsCount.Incr(name)
}
// Dao struct info of Dao
type Dao struct {
c *conf.Config
tokenURI string
cookieURI string
mc *memcache.Pool
mcLogin *memcache.Pool
client *bm.Client
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
tokenURI: c.Identify.AuthHost + _tokenURI,
cookieURI: c.Identify.AuthHost + _cookieURI,
mc: memcache.NewPool(c.Memcache),
mcLogin: memcache.NewPool(c.MemcacheLoginLog),
client: bm.NewClient(c.HTTPClient),
}
return
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
d.mc.Close()
d.mcLogin.Close()
}
// Ping ping health.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.pingMC(c); err != nil {
PromError("mc:Ping")
}
return
}
// pingMc ping memcache
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
item := memcache.Item{Key: "ping", Value: []byte{1}, Expiration: 100}
err = conn.Set(&item)
return
}

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"flag"
"os"
"testing"
"go-common/app/service/main/identify/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.identify-service")
flag.Set("conf_appid", "identify-service")
flag.Set("conf_token", "ed882ffb3c5f9ec3f4a28691a2ac3d84")
flag.Set("tree_id", "11172")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("app_id", "main.account.identify-service")
flag.Set("conf_appid", "identify-service")
flag.Set("conf_token", "15fd302391c22077da13643e11d8bab6")
flag.Set("tree_id", "11172")
flag.Set("conf_version", "server-1")
flag.Set("deploy_env", "dev")
flag.Set("conf_env", "dev")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestDao_Ping(t *testing.T) {
convey.Convey("dao ping", t, func(ctx convey.C) {
err := d.Ping(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDao_pingMC(t *testing.T) {
convey.Convey("dao ping", t, func(ctx convey.C) {
err := d.pingMC(context.Background())
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,104 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/main/identify/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
var (
loginCacheValue = []byte("1")
)
// SetAccessCache .
func (d *Dao) SetAccessCache(c context.Context, key string, res *model.IdentifyInfo) {
conn := d.mc.Get(c)
defer conn.Close()
key = cacheKey(key)
item := &memcache.Item{Key: key, Object: res, Flags: memcache.FlagProtobuf, Expiration: res.Expires}
if err := conn.Set(item); err != nil {
log.Error("identify set error(%s,%d,%v)", key, res.Expires, err)
}
}
// AccessCache .
func (d *Dao) AccessCache(c context.Context, key string) (res *model.IdentifyInfo, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key = cacheKey(key)
r, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
missedCount.Incr("access_cache")
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
res = &model.IdentifyInfo{}
if err = conn.Scan(r, res); err != nil {
PromError("mc:json解析失败")
log.Error("conn.Scan(%v) error(%v)", string(r.Value), err)
return
}
cachedCount.Incr("access_cache")
return
}
// DelCache delete access cache.
func (d *Dao) DelCache(c context.Context, key string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key = cacheKey(key)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("dao.DelCache(%s) error(%v)", key, err)
}
return
}
func cacheKey(key string) string {
return fmt.Sprintf("i_%s", key)
}
func loginCacheKey(mid int64, ip string) string {
return fmt.Sprintf("l%d%s", mid, ip)
}
// SetLoginCache set login cache
func (d *Dao) SetLoginCache(c context.Context, mid int64, ip string, expires int32) (err error) {
key := loginCacheKey(mid, ip)
conn := d.mcLogin.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Value: loginCacheValue, Flags: memcache.FlagRAW, Expiration: expires}
// use Add instead of Set
if err = conn.Set(item); err != nil {
log.Error("loginCache set error(%s,%v)", key, err)
}
return
}
// ExistMIDAndIP check is exist mid
func (d *Dao) ExistMIDAndIP(c context.Context, mid int64, ip string) (ok bool, err error) {
key := loginCacheKey(mid, ip)
conn := d.mcLogin.Get(c)
defer conn.Close()
_, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
missedCount.Incr("isExistMID")
err = nil
return false, nil
}
log.Error("loginCache conn.Get(%s) error(%v)", key, err)
return
}
return true, nil
}

View File

@@ -0,0 +1,130 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/identify/model"
"go-common/library/cache/memcache"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoSetAccessCache(t *testing.T) {
var (
c = context.Background()
key = "123"
res = &model.IdentifyInfo{Mid: 1, Csrf: "csrf", Expires: 1577811661}
)
convey.Convey("SetAccessCache", t, func(ctx convey.C) {
d.SetAccessCache(c, key, res)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
}
func TestDaoAccessCache(t *testing.T) {
var (
c = context.Background()
hitKey = "123"
missKey = "miss"
)
convey.Convey("AccessCache", t, func(ctx convey.C) {
res, err := d.AccessCache(c, hitKey)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
ctx.So(res.Mid, convey.ShouldEqual, 1)
})
})
convey.Convey("AccessCache miss", t, func(ctx convey.C) {
res, err := d.AccessCache(c, missKey)
ctx.Convey("Then err and res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoDelCache(t *testing.T) {
var (
c = context.Background()
hitKey = "123"
missKey = "miss"
)
convey.Convey("DelCache", t, func(ctx convey.C) {
err := d.DelCache(c, hitKey)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
convey.Convey("DelCache miss", t, func(ctx convey.C) {
err := d.DelCache(c, missKey)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaocacheKey(t *testing.T) {
var (
key = "1"
)
convey.Convey("cacheKey", t, func(ctx convey.C) {
p1 := cacheKey(key)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaologinCacheKey(t *testing.T) {
var (
mid = int64(1)
ip = "127.0.0.1"
)
convey.Convey("loginCacheKey", t, func(ctx convey.C) {
p1 := loginCacheKey(mid, ip)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldEqual, "l1127.0.0.1")
})
})
}
func TestDao_SetLoginCache(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
ip = "127.0.0.1"
expires = int32(1577811661)
)
convey.Convey("SetLoginCache", t, func(ctx convey.C) {
err := d.SetLoginCache(c, mid, ip, expires)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeIn, nil, memcache.ErrNotStored)
})
})
}
func TestDao_ExistMIDAndIP(t *testing.T) {
var (
c = context.Background()
mid = int64(1)
hitIP = "127.0.0.1"
missIP = "127.0.0.2"
)
convey.Convey("IsExistMID", t, func(ctx convey.C) {
ok, err := d.ExistMIDAndIP(c, mid, hitIP)
ctx.Convey("Then err should be nil.ok should be true.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldEqual, true)
})
})
convey.Convey("IsExistMID miss", t, func(ctx convey.C) {
ok, err := d.ExistMIDAndIP(c, mid, missIP)
ctx.Convey("Then err should be nil and ok should be false.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldEqual, false)
})
})
}

View File

@@ -0,0 +1,66 @@
package dao
import (
"context"
"net/http"
"net/url"
"go-common/app/service/main/identify/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// AccessCookie .
func (d *Dao) AccessCookie(c context.Context, cookie string) (res *model.IdentifyInfo, err error) {
params := url.Values{}
// new request
req, err := d.client.NewRequest(http.MethodGet, d.cookieURI, metadata.String(c, metadata.RemoteIP), params)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("Cookie", cookie)
var response struct {
Code int `json:"code"`
Data model.IdentifyInfo `json:"data"`
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != ecode.OK.Code() {
log.Warn("identify auth url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
res = &response.Data
return
}
// AccessToken .
func (d *Dao) AccessToken(c context.Context, accesskey string) (res *model.IdentifyInfo, err error) {
params := url.Values{}
params.Set("access_key", accesskey)
// new request
req, err := d.client.NewRequest(http.MethodGet, d.tokenURI, metadata.String(c, metadata.RemoteIP), params)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
var response struct {
Code int `json:"code"`
Data model.IdentifyInfo `json:"data"`
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != 0 {
log.Warn("identify auth url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
res = &response.Data
return
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoAccessCookie(t *testing.T) {
var (
c = context.Background()
cookie = "cookie=cookie"
)
convey.Convey("AccessCookie", t, func(ctx convey.C) {
res, err := d.AccessCookie(c, cookie)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoAccessToken(t *testing.T) {
var (
c = context.Background()
accesskey = "123456"
)
convey.Convey("AccessToken", t, func(ctx convey.C) {
res, err := d.AccessToken(c, accesskey)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
proto_library(
name = "model_proto",
srcs = ["model.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogo_proto"],
importpath = "go-common/app/service/main/identify/model",
proto = ":model_proto",
tags = ["manual"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = ["user_act_log.go"],
embed = [":model_go_proto"],
importpath = "go-common/app/service/main/identify/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto: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,381 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: model.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
model.proto
It has these top-level messages:
IdentifyInfo
*/
package model
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// result of http identify info.
type IdentifyInfo struct {
Mid int64 `protobuf:"varint,1,opt,name=mid,proto3" json:"mid"`
Csrf string `protobuf:"bytes,2,opt,name=csrf,proto3" json:"csrfToken"`
Expires int32 `protobuf:"varint,3,opt,name=expires,proto3" json:"expires"`
}
func (m *IdentifyInfo) Reset() { *m = IdentifyInfo{} }
func (m *IdentifyInfo) String() string { return proto.CompactTextString(m) }
func (*IdentifyInfo) ProtoMessage() {}
func (*IdentifyInfo) Descriptor() ([]byte, []int) { return fileDescriptorModel, []int{0} }
func (m *IdentifyInfo) GetMid() int64 {
if m != nil {
return m.Mid
}
return 0
}
func (m *IdentifyInfo) GetCsrf() string {
if m != nil {
return m.Csrf
}
return ""
}
func (m *IdentifyInfo) GetExpires() int32 {
if m != nil {
return m.Expires
}
return 0
}
func init() {
proto.RegisterType((*IdentifyInfo)(nil), "passport.service.identify.IdentifyInfo")
}
func (m *IdentifyInfo) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *IdentifyInfo) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Mid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintModel(dAtA, i, uint64(m.Mid))
}
if len(m.Csrf) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.Csrf)))
i += copy(dAtA[i:], m.Csrf)
}
if m.Expires != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintModel(dAtA, i, uint64(m.Expires))
}
return i, nil
}
func encodeVarintModel(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *IdentifyInfo) Size() (n int) {
var l int
_ = l
if m.Mid != 0 {
n += 1 + sovModel(uint64(m.Mid))
}
l = len(m.Csrf)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
if m.Expires != 0 {
n += 1 + sovModel(uint64(m.Expires))
}
return n
}
func sovModel(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozModel(x uint64) (n int) {
return sovModel(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *IdentifyInfo) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: IdentifyInfo: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: IdentifyInfo: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType)
}
m.Mid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Csrf", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Csrf = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Expires", wireType)
}
m.Expires = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Expires |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipModel(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthModel
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipModel(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthModel
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipModel(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthModel = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowModel = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("model.proto", fileDescriptorModel) }
var fileDescriptorModel = []byte{
// 213 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0xcd, 0x4f, 0x49,
0xcd, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x2c, 0x48, 0x2c, 0x2e, 0x2e, 0xc8, 0x2f,
0x2a, 0xd1, 0x2b, 0x4e, 0x2d, 0x2a, 0xcb, 0x4c, 0x4e, 0xd5, 0xcb, 0x4c, 0x49, 0xcd, 0x2b, 0xc9,
0x4c, 0xab, 0x94, 0xd2, 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f,
0xcf, 0x4f, 0xcf, 0xd7, 0x07, 0xeb, 0x48, 0x2a, 0x4d, 0x03, 0xf3, 0xc0, 0x1c, 0x30, 0x0b, 0x62,
0x92, 0x52, 0x31, 0x17, 0x8f, 0x27, 0x54, 0xab, 0x67, 0x5e, 0x5a, 0xbe, 0x90, 0x24, 0x17, 0x73,
0x6e, 0x66, 0x8a, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb3, 0x13, 0xfb, 0xab, 0x7b, 0xf2, 0x20, 0x6e,
0x10, 0x88, 0x10, 0x52, 0xe4, 0x62, 0x49, 0x2e, 0x2e, 0x4a, 0x93, 0x60, 0x52, 0x60, 0xd4, 0xe0,
0x74, 0xe2, 0x7d, 0x75, 0x4f, 0x9e, 0x13, 0xc4, 0x0f, 0xc9, 0xcf, 0x4e, 0xcd, 0x0b, 0x02, 0x4b,
0x09, 0xa9, 0x72, 0xb1, 0xa7, 0x56, 0x14, 0x64, 0x16, 0xa5, 0x16, 0x4b, 0x30, 0x2b, 0x30, 0x6a,
0xb0, 0x3a, 0x71, 0xbf, 0xba, 0x27, 0x0f, 0x13, 0x0a, 0x82, 0x31, 0x9c, 0xc4, 0x4f, 0x3c, 0x92,
0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x19, 0x8f, 0xe5, 0x18, 0xa2, 0x58,
0xc1, 0xbe, 0x4b, 0x62, 0x03, 0x3b, 0xca, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x73, 0x88, 0x08,
0x23, 0xed, 0x00, 0x00, 0x00,
}

View File

@@ -0,0 +1,19 @@
// +bili:type=model
syntax = "proto3";
package passport.service.identify;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "model";
// IdentifyInfo identify info
message IdentifyInfo {
// user mid
int64 mid = 1 [(gogoproto.jsontag) = "mid"];
// cookie csrf
// when token reqest this field is empty
string csrf = 2 [(gogoproto.jsontag) = "csrfToken"];
// expire time(unix timestamp)
int32 expires = 3 [(gogoproto.jsontag) = "expires"];
}

View File

@@ -0,0 +1,33 @@
package model
import (
"encoding/json"
"time"
)
type extraData struct {
IPPort string `json:"ip_port"`
}
// LoginLog user login active log
type LoginLog struct {
Mid int64 `json:"mid"`
IP string `json:"ip"`
Buvid string `json:"buvid"`
ExtraData string `json:"extra_data,omitempty"`
Business int `json:"business"`
CTime string `json:"ctime"`
}
// NewLoginLog new loginLog
func NewLoginLog(mid int64, ip string, ipport string, buvid string) *LoginLog {
ed, _ := json.Marshal(&extraData{IPPort: ipport})
return &LoginLog{
Mid: mid,
IP: ip,
Buvid: buvid,
ExtraData: string(ed),
Business: 53,
CTime: time.Now().Format("2006-01-02 15:04:05"),
}
}

View File

@@ -0,0 +1,35 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["server.go"],
importpath = "go-common/app/service/main/identify/server/grpc",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/identify/api/grpc:go_default_library",
"//app/service/main/identify/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/net/rpc/warden:go_default_library",
"@org_golang_google_grpc//: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,90 @@
package grpc
import (
"context"
"fmt"
"go-common/app/service/main/identify/api/grpc"
"go-common/app/service/main/identify/service"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/net/rpc/warden"
"google.golang.org/grpc"
)
// New Identify warden rpc server
func New(cfg *warden.ServerConfig, s *service.Service) *warden.Server {
w := warden.NewServer(cfg)
w.Use(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
if resp, err = handler(ctx, req); err != nil {
log.Infov(ctx,
log.KV("path", info.FullMethod),
log.KV("caller", metadata.String(ctx, metadata.Caller)),
log.KV("args", fmt.Sprintf("%v", req)),
log.KV("args", fmt.Sprintf("%+v", err)))
}
return
})
v1.RegisterIdentifyServer(w.Server(), &server{s})
ws, err := w.Start()
if err != nil {
panic(err)
}
return ws
}
type server struct {
svr *service.Service
}
var _ v1.IdentifyServer = &server{}
var (
emptyCookieReply = &v1.GetCookieInfoReply{
IsLogin: false,
}
emptyTokenReply = &v1.GetTokenInfoReply{
IsLogin: false,
}
)
// CookieInfo verify user info by cookie.
func (s *server) GetCookieInfo(ctx context.Context, req *v1.GetCookieInfoReq) (*v1.GetCookieInfoReply, error) {
res, err := s.svr.GetCookieInfo(ctx, req.GetCookie())
if err != nil {
if err == ecode.NoLogin {
return emptyCookieReply, nil
}
return nil, err
}
return &v1.GetCookieInfoReply{
IsLogin: true,
Mid: res.Mid,
Expires: res.Expires,
Csrf: res.Csrf,
}, nil
}
// TokenInfo verify user info by token.
func (s *server) GetTokenInfo(ctx context.Context, req *v1.GetTokenInfoReq) (*v1.GetTokenInfoReply, error) {
token := &v1.GetTokenInfoReq{
Buvid: req.Buvid,
Token: req.Token,
}
res, err := s.svr.GetTokenInfo(ctx, token)
if err != nil {
if err == ecode.NoLogin {
return emptyTokenReply, nil
}
return nil, err
}
return &v1.GetTokenInfoReply{
IsLogin: true,
Mid: res.Mid,
Expires: res.Expires,
Csrf: res.Csrf,
}, nil
}

View File

@@ -0,0 +1,40 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"identify.go",
],
importpath = "go-common/app/service/main/identify/server/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/identify/api/grpc:go_default_library",
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify: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 (
"go-common/app/service/main/identify/conf"
"go-common/app/service/main/identify/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
srv *service.Service
vfy *verify.Verify
)
// Init init
func Init(c *conf.Config, s *service.Service) {
srv = s
vfy = verify.New(c.VerifyConfig)
// engine
engIn := bm.DefaultServer(c.BM)
innerRouter(engIn)
// init inner server
if err := engIn.Start(); err != nil {
log.Error("engIn.Start error(%v)", err)
panic(err)
}
}
func innerRouter(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
group := e.Group("/x/internal/identify", vfy.Verify)
{
group.GET("cookie", accessCookie)
group.GET("token", accessToken)
group.GET("cache/del", delCache)
}
}
// ping check server ok.
func ping(c *bm.Context) {
}
// register support discovery.
func register(c *bm.Context) {
c.JSON(map[string]struct{}{}, nil)
}

View File

@@ -0,0 +1,54 @@
package http
import (
"go-common/app/service/main/identify/api/grpc"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
// const (
// _actionChangePWD = "changePwd"
// _actionLoginOut = "loginOut"
// )
func accessCookie(c *bm.Context) {
cookie := c.Request.Header.Get("Cookie")
if cookie == "" {
c.JSON(nil, ecode.NoLogin)
return
}
res, err := srv.GetCookieInfo(c, cookie)
if err == nil {
c.Set("mid", res.Mid)
}
c.JSON(res, err)
}
func accessToken(c *bm.Context) {
token := new(v1.GetTokenInfoReq)
if err := c.Bind(token); err != nil {
c.JSON(nil, ecode.NoLogin)
return
}
res, err := srv.GetTokenInfo(c, token)
if err == nil {
c.Set("mid", res.Mid)
}
c.JSON(res, err)
}
func delCache(c *bm.Context) {
// query := c.Request.Form
// action := query.Get("modifiedAttr")
// if action != _actionChangePWD && action != _actionLoginOut {
// return
// }
// key := query.Get("access_token")
// if key == "" {
// key = query.Get("session")
// }
// if key == "" {
// return
// }
c.JSON(nil, nil)
}

View File

@@ -0,0 +1,61 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"identify_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/identify/api/grpc:go_default_library",
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"identify.go",
"service.go",
],
importpath = "go-common/app/service/main/identify/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/identify/api/grpc:go_default_library",
"//app/service/main/identify/conf:go_default_library",
"//app/service/main/identify/dao:go_default_library",
"//app/service/main/identify/model:go_default_library",
"//library/cache:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/queue/databus:go_default_library",
"//vendor/github.com/pkg/errors: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,153 @@
package service
import (
"context"
"net/url"
"time"
"go-common/app/service/main/identify/api/grpc"
"go-common/app/service/main/identify/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
// cache -101
_noLoginMid = 0
_CookieSessionField = "SESSDATA"
_CookieBuvidField = "buvid3"
)
var (
_noLoginIdentify = &model.IdentifyInfo{
Mid: _noLoginMid,
Expires: 86400,
}
)
// GetCookieInfo verify user info by cookie.
func (s *Service) GetCookieInfo(c context.Context, cookie string) (res *model.IdentifyInfo, err error) {
var cache = true
ssda := readCookiesVal(cookie, _CookieSessionField)[0]
if ssda == "" {
err = ecode.NoLogin
return
}
ssda, err = url.QueryUnescape(ssda)
if err != nil {
log.Error("cookie (%s , %s) QueryUnescape error(%v)", cookie, ssda, err)
err = ecode.RequestErr
return
}
// from cache
if res, err = s.d.AccessCache(c, ssda); err != nil {
cache = false
}
if res != nil {
if res.Mid == _noLoginMid {
// check if is no login mid cache
err = ecode.NoLogin
return
}
//get buvid3 from cookie
buvid3 := readCookiesVal(cookie, _CookieBuvidField)[0]
s.loginLog(res.Mid, metadata.String(c, metadata.RemoteIP), metadata.String(c, metadata.RemotePort), buvid3)
return
}
noLoginCache := false
// from passport
if res, err = s.d.AccessCookie(c, cookie); err != nil {
if err != ecode.NoLogin && err != ecode.AccessKeyErr {
return
}
noLoginCache = true
} else if res.Expires < int32(time.Now().Unix()) {
noLoginCache = true
}
if noLoginCache {
res = _noLoginIdentify
}
if cache && res != nil {
s.cache.Save(func() {
s.d.SetAccessCache(context.Background(), ssda, res)
})
// if cache err or res nil, don't call addLoginLog
//get buvid3 from cookie
buvid3 := readCookiesVal(cookie, _CookieBuvidField)[0]
s.loginLog(res.Mid, metadata.String(c, metadata.RemoteIP), metadata.String(c, metadata.RemotePort), buvid3)
}
if res.Mid == _noLoginMid {
err = ecode.NoLogin
return
}
return
}
// GetTokenInfo verify user info by accesskey.
func (s *Service) GetTokenInfo(c context.Context, token *v1.GetTokenInfoReq) (res *model.IdentifyInfo, err error) {
var cache = true
if res, err = s.d.AccessCache(c, token.Token); err != nil {
cache = false
}
if res != nil {
if res.Mid == _noLoginMid {
err = ecode.NoLogin
return
}
s.loginLog(res.Mid, metadata.String(c, metadata.RemoteIP), metadata.String(c, metadata.RemotePort), token.Buvid)
return
}
if res, err = s.d.AccessToken(c, token.Token); err != nil {
if err != ecode.NoLogin && err != ecode.AccessKeyErr {
return
}
// no login and need cache 30s
res = _noLoginIdentify
}
if cache && res != nil {
s.cache.Save(func() {
s.d.SetAccessCache(context.Background(), token.Token, res)
})
// if cache err or res nil, don't call addLoginLog
s.loginLog(res.Mid, metadata.String(c, metadata.RemoteIP), metadata.String(c, metadata.RemotePort), token.Buvid)
}
if res.Mid == _noLoginMid {
err = ecode.NoLogin
return
}
return
}
// DelCache delete access cache when user change pwd or logout.
func (s *Service) DelCache(c context.Context, key string) (err error) {
return s.d.DelCache(c, key)
}
// SetCache delete access cache when user change pwd or logout.
func (s *Service) SetCache(c context.Context, key string, res *model.IdentifyInfo) (err error) {
s.d.SetAccessCache(c, key, res)
return
}
func (s *Service) loginLog(mid int64, ip string, ipport string, buvid string) {
if mid <= 0 || ip == "" {
return
}
s.addLoginLog(func() {
if ok, err := s.d.ExistMIDAndIP(context.Background(), mid, ip); err != nil {
return
} else if ok {
return
}
if s.isIntranetIP(ip) {
s.d.SetLoginCache(context.Background(), mid, ip, s.loginCacheExpires)
log.Warn("user ip error %s", ip)
return
}
if err := s.loginLogDataBus.Send(context.Background(), ip, model.NewLoginLog(mid, ip, ipport, buvid)); err == nil {
s.d.SetLoginCache(context.Background(), mid, ip, s.loginCacheExpires)
}
})
}

View File

@@ -0,0 +1,88 @@
package service
import (
"context"
"testing"
"go-common/app/service/main/identify/api/grpc"
"go-common/app/service/main/identify/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_SetCache(t *testing.T) {
Convey("test set cache ", t, func() {
once.Do(startService)
var (
accessKey = "11111111"
res = &model.IdentifyInfo{
Mid: 1523454,
Expires: 111111,
Csrf: "1111",
}
err error
c = context.Background()
)
err = s.SetCache(c, accessKey, res)
So(err, ShouldBeNil)
})
}
func TestService_AccessCookie(t *testing.T) {
Convey("test GetCookieInfo ", t, func() {
once.Do(startService)
var (
cookie = "SESSDATA=11111111;buvid3=fasr435"
res *model.IdentifyInfo
err error
c = context.Background()
)
res, err = s.GetCookieInfo(c, cookie)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_AccessToken(t *testing.T) {
Convey("test GetTokenInfo", t, func() {
once.Do(startService)
var (
token = &v1.GetTokenInfoReq{}
c = context.Background()
res *model.IdentifyInfo
err error
)
token.Token = "11111111"
token.Buvid = "fert32434"
res, err = s.GetTokenInfo(c, token)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_LoginLog(t *testing.T) {
Convey("test login log", t, func() {
once.Do(startService)
var (
mid = 1244545
ip = "15.1.1.1"
ipPort = "2434"
buvid = "2134435fderf"
)
s.loginLog(int64(mid), ip, ipPort, buvid)
})
}
func TestService_DelCache(t *testing.T) {
Convey("test del cache", t, func() {
once.Do(startService)
var (
accessKey = "11111111"
err error
c = context.Background()
)
err = s.DelCache(c, accessKey)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,152 @@
package service
import (
"context"
"net"
"strings"
"go-common/app/service/main/identify/conf"
"go-common/app/service/main/identify/dao"
"go-common/library/cache"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/pkg/errors"
)
var (
emptyStringArray = []string{""}
)
// Service is a identify service.
type Service struct {
c *conf.Config
d *dao.Dao
// cache proc
cache *cache.Cache
// login log
loginlogchan chan func()
// loginLogDataBus
loginLogDataBus *databus.Databus
// loginCacheExpires
loginCacheExpires int32
// intranetCIDR
intranetCIDR []*net.IPNet
}
// New new a identify service.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
d: dao.New(c),
cache: cache.New(1, 1024),
// login log chan
loginlogchan: make(chan func(), 10240),
loginLogDataBus: databus.New(c.DataBus.UserLog),
// loginCacheExpires
loginCacheExpires: 3600,
}
cidrs := make([]*net.IPNet, 0, len(c.Identify.IntranetCIDR))
for _, raw := range c.Identify.IntranetCIDR {
_, inet, err := net.ParseCIDR(raw)
if err != nil {
panic(errors.Wrapf(err, "Invalid CIDR: %s", raw))
}
cidrs = append(cidrs, inet)
}
s.intranetCIDR = cidrs
if c.Identify.LoginCacheExpires > 0 {
s.loginCacheExpires = c.Identify.LoginCacheExpires
}
for i := 0; i < s.c.Identify.LoginLogConsumerSize; i++ {
go func() {
for f := range s.loginlogchan {
f()
}
}()
}
return
}
// Close dao.
func (s *Service) Close() {
s.d.Close()
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return s.d.Ping(c)
}
func (s *Service) addLoginLog(f func()) {
select {
case s.loginlogchan <- f:
default:
log.Warn("loginlogchan chan full")
}
}
// readCookiesVal parses all "Cookie" values from the input line and
// returns the successfully parsed values.
//
// if filter isn't empty, only cookies of that name are returned
func readCookiesVal(line, filter string) []string {
if line == "" {
return emptyStringArray
}
var cookies []string
parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
return emptyStringArray
}
// Per-line attributes
for i := 0; i < len(parts); i++ {
parts[i] = strings.TrimSpace(parts[i])
if len(parts[i]) == 0 {
continue
}
name, val := parts[i], ""
if j := strings.Index(name, "="); j >= 0 {
name, val = name[:j], name[j+1:]
}
// if !isCookieNameValid(name) {
// continue
// }
if filter != "" && filter != name {
continue
}
val, ok := parseCookieValue(val, true)
if !ok {
continue
}
cookies = append(cookies, val)
}
if len(cookies) == 0 {
return emptyStringArray
}
return cookies
}
func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
// Strip the quotes, if present.
if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' {
raw = raw[1 : len(raw)-1]
}
// for i := 0; i < len(raw); i++ {
// if !validCookieValueByte(raw[i]) {
// return "", false
// }
// }
return raw, true
}
func (s *Service) isIntranetIP(ip string) (exists bool) {
for _, c := range s.intranetCIDR {
if c.Contains(net.ParseIP(ip)) {
exists = true
return
}
}
return
}

View File

@@ -0,0 +1,56 @@
package service
import (
"sync"
"testing"
"go-common/app/service/main/identify/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
once sync.Once
s *Service
)
func startService() {
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
func TestService_ReadCookiesVal(t *testing.T) {
Convey("test read cookies val", t, func() {
vals0 := readCookiesVal("SESSDATA=123456", "SESSDATA")
So(len(vals0), ShouldEqual, 1)
So(vals0[0], ShouldEqual, "123456")
vals1 := readCookiesVal("SESSDATA=123456;sid=456", "SESSDATA")
So(len(vals1), ShouldEqual, 1)
So(vals1[0], ShouldEqual, "123456")
vals2 := readCookiesVal("SESSDATA=123456;sid=456", "NOTEXIST")
So(len(vals2), ShouldEqual, 1)
So(vals2[0], ShouldEqual, "")
vals3 := readCookiesVal("fts=1531043495; im_notify_type_9119166=0; rpdid=iwqspsxomwdoskowppkww; UM_distinctid=1647a1d280b9b7-0a08c4306c3a24-16386952-232800-1647a1d280c12b; LIVE_BUVID=51d9a8b51edd9c9fd23a3c894f447327; LIVE_BUVID__ckMd5=9f17f524c5a8688a; sid=bzfd5icm; pgv_pvi=3323167744; pos=44; im_local_unread_1=0; pgv_si=s4746899456; buvid3=1B00778D-FC70-43F5-8BC9-3C1020636B026695infoc; CURRENT_QUALITY=80; finger=14bc3c4e; bp_t_offset_18478831=149485967370985408; DedeUserID=9119166; DedeUserID__ckMd5=c11479f809369580; SESSDATA=22f15449%2C1536288045%2Ca05af0ad; bili_jct=4801fa7ff4587a8a6efb588be1b1a915; _ga=GA1.2.689403130.1533818051; stardustvideo=1; BANGUMI_SS_6360_REC=243804; CURRENT_FNVAL=8; im_local_unread_9119166=0; im_seqno_9119166=24530; bp_t_offset_9119166=156097786055309344; msource=PCbanner; _dfcaptcha=5f9c3f275dcdf853b0ff78d902bbfdd9", "SESSDATA")
So(len(vals3), ShouldEqual, 1)
So(vals3[0], ShouldEqual, "22f15449%2C1536288045%2Ca05af0ad")
})
}
func TestService_isIntranetIP(t *testing.T) {
once.Do(startService)
Convey("", t, func() {
ok := false
ok = s.isIntranetIP("10.255.255.255")
So(ok, ShouldBeTrue)
ok = s.isIntranetIP("172.31.255.255")
So(ok, ShouldBeTrue)
ok = s.isIntranetIP("172.32.255.255")
So(ok, ShouldBeFalse)
ok = s.isIntranetIP("192.168.255.255")
So(ok, ShouldBeTrue)
ok = s.isIntranetIP("192.169.0.1")
So(ok, ShouldBeFalse)
})
}