From 3b474a056ea35196ce5d2a5f297eafa11295a95d Mon Sep 17 00:00:00 2001
From: liujiandao <274878379@qq.com>
Date: 星期三, 22 十一月 2023 14:23:13 +0800
Subject: [PATCH] 添加登录功能

---
 request/jwt.go           |   20 +
 go.mod                   |    3 
 pkg/ecode/code.go        |   21 +
 pkg/contextx/contextx.go |   97 ++++++++
 constvar/const.go        |    9 
 pkg/logx/json.go         |   91 +++++++
 pkg/logx/service.go      |   49 ++++
 go.sum                   |   13 
 middleware/utils.go      |   60 +++++
 pkg/logx/console.go      |   89 +++++++
 middleware/jwt.go        |   39 +++
 pkg/logx/index.go        |  158 +++++++++++++
 initialize/router.go     |    8 
 pkg/ecode/msg.go         |   24 ++
 14 files changed, 669 insertions(+), 12 deletions(-)

diff --git a/constvar/const.go b/constvar/const.go
new file mode 100644
index 0000000..384dbfa
--- /dev/null
+++ b/constvar/const.go
@@ -0,0 +1,9 @@
+package constvar
+
+type UserType int
+
+const (
+	UserTypeSuper   UserType = iota + 1 // 瓒呯骇绠$悊鍛�
+	UserTypePrimary                     // 涓昏处鎴�
+	UserTypeSub                         // 瀛愯处鎴�
+)
diff --git a/go.mod b/go.mod
index ba23ae5..879a5a1 100644
--- a/go.mod
+++ b/go.mod
@@ -3,11 +3,13 @@
 go 1.18
 
 require (
+	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/fsnotify/fsnotify v1.6.0
 	github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6
 	github.com/gin-gonic/gin v1.9.1
 	github.com/glebarez/sqlite v1.8.0
 	github.com/go-sql-driver/mysql v1.7.1
+	github.com/golang-jwt/jwt/v4 v4.5.0
 	github.com/h2non/filetype v1.1.3
 	github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
 	github.com/redis/go-redis/v9 v9.0.5
@@ -23,6 +25,7 @@
 	golang.org/x/sync v0.3.0
 	google.golang.org/grpc v1.55.0
 	google.golang.org/protobuf v1.30.0
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 	gorm.io/driver/mysql v1.5.1
 	gorm.io/driver/postgres v1.5.2
 	gorm.io/driver/sqlserver v1.5.1
diff --git a/go.sum b/go.sum
index 5995390..92c4d46 100644
--- a/go.sum
+++ b/go.sum
@@ -45,7 +45,6 @@
 github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
 github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
 github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
-github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -73,6 +72,8 @@
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
@@ -140,10 +141,10 @@
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
 github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
 github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
@@ -226,16 +227,10 @@
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
-github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
 github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
-github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
-github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8=
 github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU=
 github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8=
 github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
@@ -769,6 +764,8 @@
 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/initialize/router.go b/initialize/router.go
index 4b390f7..584dbf3 100644
--- a/initialize/router.go
+++ b/initialize/router.go
@@ -2,6 +2,7 @@
 
 import (
 	"net/http"
+	"srm/middleware"
 	"srm/router/purchase"
 
 	"github.com/gin-gonic/gin"
@@ -25,16 +26,15 @@
 	global.GVA_LOG.Info("register swagger handler")
 	// 鏂逛究缁熶竴娣诲姞璺敱缁勫墠缂� 澶氭湇鍔″櫒涓婄嚎浣跨敤
 
-	PublicGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
+	PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
 	{
 		// 鍋ュ悍鐩戞祴
-		PublicGroup.GET("/health", func(c *gin.Context) {
+		PrivateGroup.GET("/health", func(c *gin.Context) {
 			c.JSON(http.StatusOK, "ok")
 		})
 		//systemRouter.InitInitRouter(PublicGroup) // 鑷姩鍒濆鍖栫浉鍏�
 	}
-
-	PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix)
+	PrivateGroup.Use(middleware.JWTAuth())
 	{
 		systemRouter.InitSystemRouter(PrivateGroup) // system鐩稿叧璺敱
 		//exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 鏂囦欢涓婁紶涓嬭浇鍔熻兘璺敱
diff --git a/middleware/jwt.go b/middleware/jwt.go
new file mode 100644
index 0000000..42ce6e0
--- /dev/null
+++ b/middleware/jwt.go
@@ -0,0 +1,39 @@
+package middleware
+
+import (
+	"github.com/gin-gonic/gin"
+	"srm/pkg/contextx"
+	"srm/pkg/ecode"
+	"strings"
+)
+
+func JWTAuth() gin.HandlerFunc {
+	return func(c *gin.Context) {
+		ctx := new(contextx.Context).SetCtx(c)
+		// 鎴戜滑杩欓噷jwt閴存潈鍙栧ご閮ㄤ俊鎭� Authorization 鐧诲綍鏃跺洖杩斿洖token淇℃伅 杩欓噷鍓嶇闇�瑕佹妸token瀛樺偍鍒癱ookie鎴栬�呮湰鍦發ocalStorage涓� 涓嶈繃闇�瑕佽窡鍚庣鍗忓晢杩囨湡鏃堕棿 鍙互绾﹀畾鍒锋柊浠ょ墝鎴栬�呴噸鏂扮櫥褰�
+		token := c.Request.Header.Get("Authorization")
+		if token == "" {
+			ctx.Fail(ecode.JWTEmpty)
+			c.Abort()
+			return
+		}
+		slices := strings.Split(token, " ")
+		if len(slices) == 2 {
+			token = slices[1]
+		}
+		j := NewJWT()
+		// parseToken 瑙f瀽token鍖呭惈鐨勪俊鎭�
+		claims, err := j.ParseToken(token)
+		if err != nil {
+			if err == TokenExpired {
+				c.Next()
+				return
+			}
+			c.Next()
+			return
+		}
+
+		c.Set("claims", claims)
+		c.Next()
+	}
+}
diff --git a/middleware/utils.go b/middleware/utils.go
new file mode 100644
index 0000000..190a77a
--- /dev/null
+++ b/middleware/utils.go
@@ -0,0 +1,60 @@
+package middleware
+
+import (
+	"errors"
+	"github.com/golang-jwt/jwt/v4"
+	"srm/request"
+)
+
+type JWT struct {
+	SigningKey []byte
+}
+
+var (
+	TokenExpired     = errors.New("Token is expired")
+	TokenNotValidYet = errors.New("Token not active yet")
+	TokenMalformed   = errors.New("That's not even a token")
+	TokenInvalid     = errors.New("Couldn't handle this token:")
+)
+
+func NewJWT() *JWT {
+	return &JWT{
+		[]byte("327a9457-899a-481e-8b30-58cc97e5b808"),
+	}
+}
+
+// CreateToken 鍒涘缓涓�涓猼oken
+func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) {
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
+	return token.SignedString(j.SigningKey)
+}
+
+// ParseToken 瑙f瀽token
+func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) {
+	token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
+		return j.SigningKey, nil
+	})
+	if err != nil {
+		if ve, ok := err.(*jwt.ValidationError); ok {
+			if ve.Errors&jwt.ValidationErrorMalformed != 0 {
+				return nil, TokenMalformed
+			} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
+				// Token is expired
+				return nil, TokenExpired
+			} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
+				return nil, TokenNotValidYet
+			} else {
+				return nil, TokenInvalid
+			}
+		}
+	}
+	if token != nil {
+		if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
+			return claims, nil
+		}
+		return nil, TokenInvalid
+
+	} else {
+		return nil, TokenInvalid
+	}
+}
diff --git a/pkg/contextx/contextx.go b/pkg/contextx/contextx.go
new file mode 100644
index 0000000..958df06
--- /dev/null
+++ b/pkg/contextx/contextx.go
@@ -0,0 +1,97 @@
+package contextx
+
+import (
+	"github.com/gin-gonic/gin"
+	"net/http"
+	"srm/pkg/ecode"
+	"srm/pkg/logx"
+)
+
+type (
+	Context struct {
+		ctx       *gin.Context
+		paramsMap map[string]interface{}
+	}
+
+	Response struct {
+		Code int         `json:"code"`
+		Data interface{} `json:"data"`
+		Msg  string      `json:"msg"`
+	}
+)
+
+func NewContext(ctx *gin.Context, params interface{}) (r *Context, isAllow bool) {
+	r = &Context{
+		ctx: ctx,
+	}
+	if r.ctx.Request.Method == "OPTIONS" {
+		r.ctx.String(http.StatusOK, "")
+		return
+	}
+
+	defer func() {
+		query := r.ctx.Request.URL.RawQuery
+		if query != "" {
+			query = "?" + query
+		}
+		urlPath := r.ctx.Request.URL.Path
+		logx.Infof("%s | %s %s | uid: %s | %+v", ctx.ClientIP(), r.ctx.Request.Method, urlPath+query, r.GetUserId(), params)
+	}()
+
+	// validate params
+	if params != nil {
+		if err := r.ctx.ShouldBind(params); err != nil {
+			r.Fail(ecode.ParamsErr)
+			return
+		}
+	}
+	isAllow = true
+	return
+}
+
+func (slf *Context) GetRequestPath() (r string) {
+	r = slf.ctx.Request.URL.Path
+	return
+}
+
+func (slf *Context) GetUserId() (r string) {
+	v := slf.paramsMap["userId"]
+	switch v.(type) {
+	case string:
+		r = v.(string)
+	}
+	return
+}
+
+func (slf *Context) Result(code int, data interface{}, msg string) {
+	slf.ctx.JSON(http.StatusOK, Response{
+		Code: code,
+		Data: data,
+		Msg:  msg,
+	})
+}
+
+func (slf *Context) Ok() {
+	slf.Result(ecode.OK, map[string]interface{}{}, "")
+}
+
+func (slf *Context) OkWithDetailed(data interface{}) {
+	slf.Result(ecode.OK, data, "")
+}
+
+func (slf *Context) Fail(errCode int) {
+	slf.Result(errCode, map[string]interface{}{}, ecode.GetMsg(errCode))
+}
+
+func (slf *Context) FailWithDetailed(errCode int, data interface{}) {
+	slf.Result(errCode, data, ecode.GetMsg(errCode))
+}
+
+func (slf *Context) GetCtx() *gin.Context {
+	return slf.ctx
+}
+
+func (slf *Context) SetCtx(c *gin.Context) *Context {
+	slf.ctx = c
+	return slf
+}
diff --git a/pkg/ecode/code.go b/pkg/ecode/code.go
new file mode 100644
index 0000000..aa74251
--- /dev/null
+++ b/pkg/ecode/code.go
@@ -0,0 +1,21 @@
+package ecode
+
+const (
+	OK = 200
+
+	UnknownErr            = 2001 // 鏈煡閿欒
+	DBErr                 = 2002 // db閿欒
+	RedisErr              = 2003 // redis閿欒
+	ParamsErr             = 2004 // 璇锋眰鍙傛暟閿欒
+	UserNotExist          = 2005 // 鐢ㄦ埛涓嶅瓨鍦�
+	PasswordErr           = 2006 // 瀵嗙爜閿欒
+	UserForbidden         = 2007 // 鐢ㄦ埛琚鐢�
+	CaptchaGenerateFailed = 2008 // 楠岃瘉鐮佺敓鎴愬け璐�
+	CaptchaErr            = 2009 // 楠岃瘉鐮侀敊璇�
+	CreateTokenErr        = 2010 // 鍒涘缓token澶辫触
+	JWTInBlackList        = 2011 // JWT鍦ㄧ櫧鍚嶅崟
+	JWTDisabled           = 2012 // JWT澶辨晥
+	JWTEmpty              = 2013 // JWT涓虹┖
+	JWTExpire             = 2014 // JWT杩囨湡
+	JWTParseErr           = 2015 // JWT瑙f瀽澶辫触
+)
diff --git a/pkg/ecode/msg.go b/pkg/ecode/msg.go
new file mode 100644
index 0000000..9b5ebe5
--- /dev/null
+++ b/pkg/ecode/msg.go
@@ -0,0 +1,24 @@
+package ecode
+
+var MsgFlags = map[int]string{
+	UnknownErr:            "鏈煡閿欒",
+	DBErr:                 "db閿欒",
+	RedisErr:              "redis閿欒",
+	ParamsErr:             "璇锋眰鍙傛暟閿欒",
+	UserNotExist:          "鐢ㄦ埛涓嶅瓨鍦�",
+	PasswordErr:           "瀵嗙爜閿欒",
+	UserForbidden:         "鐢ㄦ埛琚鐢�",
+	CaptchaGenerateFailed: "楠岃瘉鐮佺敓鎴愬け璐�",
+	CaptchaErr:            "楠岃瘉鐮侀敊璇�",
+	CreateTokenErr:        "鍒涘缓token澶辫触",
+	JWTInBlackList:        "JWT鍦ㄧ櫧鍚嶅崟",
+	JWTDisabled:           "JWT澶辨晥",
+	JWTEmpty:              "JWT涓虹┖",
+	JWTExpire:             "JWT杩囨湡",
+	JWTParseErr:           "JWT瑙f瀽澶辫触",
+}
+
+func GetMsg(errCode int) (errMsg string) {
+	errMsg, _ = MsgFlags[errCode]
+	return
+}
diff --git a/pkg/logx/console.go b/pkg/logx/console.go
new file mode 100644
index 0000000..fe1d18a
--- /dev/null
+++ b/pkg/logx/console.go
@@ -0,0 +1,89 @@
+package logx
+
+import (
+	"fmt"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+	"time"
+)
+
+type ConsoleLog struct {
+	val string
+}
+
+func NewConsoleLog() Encoder {
+	return new(ConsoleLog)
+}
+
+// Config 鑷畾涔夐厤缃�.
+func (slf *ConsoleLog) Config() zapcore.Encoder {
+	var (
+		cfg = zap.NewProductionEncoderConfig()
+	)
+
+	// 鏃堕棿鏍煎紡鑷畾涔�
+	cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
+		enc.AppendString("[" + t.Format("2006-01-02 15:04:05") + "]")
+	}
+	// 鎵撳嵃璺緞鑷畾涔�
+	cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) {
+		encoder.AppendString("[" + getFilePath(caller) + "]")
+	}
+	// 绾у埆鏄剧ず鑷畾涔�
+	cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
+		encoder.AppendString("[" + level.String() + "]")
+	}
+	return zapcore.NewConsoleEncoder(cfg)
+}
+
+// WithKey 娣诲姞鍗曚釜閿�.
+func (slf *ConsoleLog) WithKey(key string) Encoder {
+	slf.val = slf.val + "[" + key + "]    "
+	return slf
+}
+
+// WithField 娣诲姞瀛楁.
+func (slf *ConsoleLog) WithField(key, val string) Encoder {
+	slf.val = slf.val + fmt.Sprintf("[%s:%s]    ", key, val)
+	return slf
+}
+
+func (slf *ConsoleLog) Debug(msg string) {
+	_logger.Debug(slf.val + msg)
+}
+
+func (slf *ConsoleLog) Debugf(format string, v ...interface{}) {
+	_logger.Debug(fmt.Sprintf(slf.val+format, v...))
+}
+
+func (slf *ConsoleLog) Info(msg string) {
+	_logger.Info(slf.val + msg)
+}
+
+func (slf *ConsoleLog) Infof(format string, v ...interface{}) {
+	_logger.Info(fmt.Sprintf(slf.val+format, v...))
+}
+
+func (slf *ConsoleLog) Warn(msg string) {
+	_logger.Warn(slf.val + msg)
+}
+
+func (slf *ConsoleLog) Warnf(format string, v ...interface{}) {
+	_logger.Warn(fmt.Sprintf(slf.val+format, v...))
+}
+
+func (slf *ConsoleLog) Error(msg string) {
+	_logger.Error(slf.val + msg)
+}
+
+func (slf *ConsoleLog) Errorf(format string, v ...interface{}) {
+	_logger.Error(fmt.Sprintf(slf.val+format, v...))
+}
+
+func (slf *ConsoleLog) Fatal(msg string) {
+	_logger.Fatal(slf.val + msg)
+}
+
+func (slf *ConsoleLog) Fatalf(format string, v ...interface{}) {
+	_logger.Fatal(fmt.Sprintf(slf.val+format, v...))
+}
diff --git a/pkg/logx/index.go b/pkg/logx/index.go
new file mode 100644
index 0000000..42e4213
--- /dev/null
+++ b/pkg/logx/index.go
@@ -0,0 +1,158 @@
+package logx
+
+import (
+	"go.uber.org/zap"
+	"go.uber.org/zap/buffer"
+	"go.uber.org/zap/zapcore"
+	"gopkg.in/natefinch/lumberjack.v2"
+	"os"
+	"path"
+	"strings"
+)
+
+type (
+	Conf struct {
+		Path    string // 鏃ュ織璺緞
+		Encoder string // 缂栫爜鍣ㄩ�夋嫨
+	}
+	logItem struct {
+		FileName string
+		Level    zap.LevelEnablerFunc
+	}
+	Encoder interface {
+		Config() zapcore.Encoder
+		WithKey(key string) Encoder
+		WithField(key, val string) Encoder
+		Debug(msg string)
+		Debugf(format string, v ...interface{})
+		Info(msg string)
+		Infof(format string, v ...interface{})
+		Warn(msg string)
+		Warnf(format string, v ...interface{})
+		Error(msg string)
+		Errorf(format string, v ...interface{})
+		Fatal(msg string)
+		Fatalf(format string, v ...interface{})
+	}
+)
+
+var (
+	maxSize    = 200 // 姣忎釜鏃ュ織鏂囦欢鏈�澶у昂瀵�200M
+	maxBackups = 20  // 鏃ュ織鏂囦欢鏈�澶氫繚瀛�20涓浠�
+	maxAge     = 30  // 淇濈暀鏈�澶уぉ鏁�
+	_logger    *zap.Logger
+	_pool      = buffer.NewPool()
+	c          Conf
+
+	ConsoleEncoder = "console" // 鎺у埗鍙拌緭鍑�
+	JsonEncoder    = "json"    // json杈撳嚭
+)
+
+// Init 鍒濆鍖栨棩蹇�.
+func Init(conf Conf) {
+	c = conf
+	prefix, suffix := getFileSuffixPrefix(c.Path)
+
+	infoPath := path.Join(prefix + ".info" + suffix)
+	errPath := path.Join(prefix + ".err" + suffix)
+	items := []logItem{
+		{
+			FileName: infoPath,
+			Level: func(level zapcore.Level) bool {
+				return level <= zap.InfoLevel
+			},
+		},
+		{
+			FileName: errPath,
+			Level: func(level zapcore.Level) bool {
+				return level > zap.InfoLevel
+			},
+		},
+	}
+
+	NewLogger(items)
+}
+
+// NewLogger 鏃ュ織.
+func NewLogger(items []logItem) {
+	var (
+		cfg   zapcore.Encoder
+		cores []zapcore.Core
+	)
+	switch c.Encoder {
+	case JsonEncoder:
+		cfg = NewJsonLog().Config()
+	case ConsoleEncoder:
+		cfg = NewConsoleLog().Config()
+	default:
+		cfg = NewConsoleLog().Config()
+	}
+
+	for _, v := range items {
+		hook := lumberjack.Logger{
+			Filename:   v.FileName,
+			MaxSize:    maxSize,    // 姣忎釜鏃ュ織鏂囦欢淇濆瓨鐨勬渶澶у昂瀵� 鍗曚綅锛歁
+			MaxBackups: maxBackups, // 鏃ュ織鏂囦欢鏈�澶氫繚瀛樺灏戜釜澶囦唤
+			MaxAge:     maxAge,     // 鏂囦欢鏈�澶氫繚瀛樺灏戝ぉ
+			Compress:   true,       // 鏄惁鍘嬬缉
+			LocalTime:  true,       // 澶囦唤鏂囦欢鍚嶆湰鍦�/UTC鏃堕棿
+		}
+		core := zapcore.NewCore(
+			cfg, // 缂栫爜鍣ㄩ厤缃�;
+			zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // 鎵撳嵃鍒版帶鍒跺彴鍜屾枃浠�
+			v.Level, // 鏃ュ織绾у埆
+		)
+		cores = append(cores, core)
+	}
+
+	// 寮�鍚紑鍙戞ā寮忥紝鍫嗘爤璺熻釜
+	caller := zap.AddCaller()
+	// 寮�鍙戞ā寮�
+	development := zap.Development()
+	// 浜屾灏佽
+	skip := zap.AddCallerSkip(1)
+	// 鏋勯�犳棩蹇�
+	_logger = zap.New(zapcore.NewTee(cores...), caller, development, skip)
+	return
+}
+
+// GetEncoder 鑾峰彇鑷畾涔夌紪鐮佸櫒.
+func GetEncoder() Encoder {
+	switch c.Encoder {
+	case JsonEncoder:
+		return NewJsonLog()
+	case ConsoleEncoder:
+		return NewConsoleLog()
+	default:
+		return NewConsoleLog()
+	}
+}
+
+// GetLogger 鑾峰彇鏃ュ織璁板綍鍣�.
+func GetLogger() *zap.Logger {
+	return _logger
+}
+
+// getFileSuffixPrefix 鏂囦欢璺緞鍒囧壊
+func getFileSuffixPrefix(fileName string) (prefix, suffix string) {
+	paths, _ := path.Split(fileName)
+	base := path.Base(fileName)
+	suffix = path.Ext(fileName)
+	prefix = strings.TrimSuffix(base, suffix)
+	prefix = path.Join(paths, prefix)
+	return
+}
+
+// getFilePath 鑷畾涔夎幏鍙栨枃浠惰矾寰�.
+func getFilePath(ec zapcore.EntryCaller) string {
+	if !ec.Defined {
+		return "undefined"
+	}
+	buf := _pool.Get()
+	buf.AppendString(ec.Function)
+	buf.AppendByte(':')
+	buf.AppendInt(int64(ec.Line))
+	caller := buf.String()
+	buf.Free()
+	return caller
+}
diff --git a/pkg/logx/json.go b/pkg/logx/json.go
new file mode 100644
index 0000000..1d7d361
--- /dev/null
+++ b/pkg/logx/json.go
@@ -0,0 +1,91 @@
+package logx
+
+import (
+	"fmt"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+	"time"
+)
+
+type JsonLog struct {
+	fields []zap.Field
+	val    string
+}
+
+// NewJsonLog  鑷畾涔夋坊鍔爈og field.
+func NewJsonLog() Encoder {
+	return &JsonLog{fields: make([]zap.Field, 0)}
+}
+
+// Config 鑷畾涔夐厤缃�.
+func (slf *JsonLog) Config() zapcore.Encoder {
+	var (
+		cfg = zap.NewProductionEncoderConfig()
+	)
+
+	// 鏃堕棿鏍煎紡鑷畾涔�
+	cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
+		enc.AppendString(t.Format("2006-01-02 15:04:05"))
+	}
+	// 鎵撳嵃璺緞鑷畾涔�
+	cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) {
+		encoder.AppendString(getFilePath(caller))
+	}
+	// 绾у埆鏄剧ず鑷畾涔�
+	cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) {
+		encoder.AppendString(level.String())
+	}
+	return zapcore.NewJSONEncoder(cfg)
+}
+
+// WithKey 娣诲姞鍗曚釜閿�.
+func (slf *JsonLog) WithKey(key string) Encoder {
+	slf.val = slf.val + key + " "
+	return slf
+}
+
+// WithField 娣诲姞瀛楁.
+func (slf *JsonLog) WithField(key, val string) Encoder {
+	slf.fields = append(slf.fields, zap.String(key, val))
+	return slf
+}
+
+func (slf *JsonLog) Debug(msg string) {
+	_logger.Debug(slf.val+msg, slf.fields...)
+}
+
+func (slf *JsonLog) Debugf(format string, v ...interface{}) {
+	_logger.Debug(fmt.Sprintf(slf.val+format, v...), slf.fields...)
+}
+
+func (slf *JsonLog) Info(msg string) {
+	_logger.Info(slf.val+msg, slf.fields...)
+}
+
+func (slf *JsonLog) Infof(format string, v ...interface{}) {
+	_logger.Info(fmt.Sprintf(slf.val+format, v...), slf.fields...)
+}
+
+func (slf *JsonLog) Warn(msg string) {
+	_logger.Warn(slf.val+msg, slf.fields...)
+}
+
+func (slf *JsonLog) Warnf(format string, v ...interface{}) {
+	_logger.Warn(fmt.Sprintf(slf.val+format, v...), slf.fields...)
+}
+
+func (slf *JsonLog) Error(msg string) {
+	_logger.Error(slf.val+msg, slf.fields...)
+}
+
+func (slf *JsonLog) Errorf(format string, v ...interface{}) {
+	_logger.Error(fmt.Sprintf(slf.val+format, v...), slf.fields...)
+}
+
+func (slf *JsonLog) Fatal(msg string) {
+	_logger.Fatal(slf.val+msg, slf.fields...)
+}
+
+func (slf *JsonLog) Fatalf(format string, v ...interface{}) {
+	_logger.Fatal(fmt.Sprintf(slf.val+format, v...), slf.fields...)
+}
diff --git a/pkg/logx/service.go b/pkg/logx/service.go
new file mode 100644
index 0000000..4416eee
--- /dev/null
+++ b/pkg/logx/service.go
@@ -0,0 +1,49 @@
+package logx
+
+import (
+	"fmt"
+)
+
+func Sync() {
+	_ = _logger.Sync()
+}
+
+func Debug(msg string) {
+	_logger.Debug(msg)
+}
+
+func Debugf(format string, v ...interface{}) {
+	_logger.Debug(fmt.Sprintf(format, v...))
+}
+
+func Info(msg string) {
+	_logger.Info(msg)
+}
+
+func Infof(format string, v ...interface{}) {
+	_logger.Info(fmt.Sprintf(format, v...))
+}
+
+func Warn(msg string) {
+	_logger.Warn(msg)
+}
+
+func Warnf(format string, v ...interface{}) {
+	_logger.Warn(fmt.Sprintf(format, v...))
+}
+
+func Error(msg string) {
+	_logger.Error(msg)
+}
+
+func Errorf(format string, v ...interface{}) {
+	_logger.Error(fmt.Sprintf(format, v...))
+}
+
+func Fatal(msg string) {
+	_logger.Fatal(msg)
+}
+
+func Fatalf(format string, v ...interface{}) {
+	_logger.Fatal(fmt.Sprintf(format, v...))
+}
diff --git a/request/jwt.go b/request/jwt.go
new file mode 100644
index 0000000..0e3b5a4
--- /dev/null
+++ b/request/jwt.go
@@ -0,0 +1,20 @@
+package request
+
+import (
+	"github.com/dgrijalva/jwt-go"
+	"srm/constvar"
+)
+
+// Custom claims structure
+type CustomClaims struct {
+	BaseClaims
+	BufferTime int64
+	jwt.StandardClaims
+}
+
+type BaseClaims struct {
+	UserId   string
+	Username string
+	ParentId string
+	UserType constvar.UserType
+}

--
Gitblit v1.8.0