From 8882522b0df1634ced40d21dc9a5fad222496af6 Mon Sep 17 00:00:00 2001 From: vaspike Date: Mon, 25 Apr 2022 00:45:49 +0800 Subject: [PATCH 1/5] feat(Auth): Init auth module --- auth.go | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 ++ response.go | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 auth.go diff --git a/auth.go b/auth.go new file mode 100644 index 0000000..142fd59 --- /dev/null +++ b/auth.go @@ -0,0 +1,89 @@ +package nutshttp + +import ( + "errors" + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" + "time" +) + +type CheckFunc func(string) bool + +type Option struct { + ExpireDuration time.Duration + Issuer string + SigningMethod jwt.SigningMethod + checkFunc CheckFunc +} + +//var checkFunc CheckFunc +var option Option + +func defaultOptAndCheckFunc() Option { + return Option{ + ExpireDuration: time.Hour * 4, + Issuer: "nutsdb.nutsdb-http", + SigningMethod: jwt.SigningMethodES512, + checkFunc: func(s string) bool { + return true + }, + } +} + +type TokenClaims struct { + Cert string `json:"cert"` + jwt.StandardClaims +} + +var secret = []byte("78") + +func GenerateToken(cert string) (string, error) { + claims := TokenClaims{ + cert, + jwt.StandardClaims{ + ExpiresAt: time.Now().Add(option.ExpireDuration).Unix(), + Issuer: option.Issuer, + }} + token := jwt.NewWithClaims(option.SigningMethod, claims) + signedToken, err := token.SignedString(secret) + if err != nil { + return "", err + } + return signedToken, nil +} + +func CheckToken(tokenStr string) (*TokenClaims, error) { + token, err := jwt.ParseWithClaims(tokenStr, &TokenClaims{}, func(token *jwt.Token) (interface{}, error) { + return secret, nil + }) + if err != nil { + return nil, err + } + if claims, ok := token.Claims.(*TokenClaims); ok && token.Valid { + return claims, nil + } + return nil, errors.New("invalid token") +} + +func handler(c *gin.Context) { + if &option == nil { + panic(errors.New("invalid auth option")) + } + var cert string + err := c.ShouldBind(&cert) + if err != nil { + WriteError(c, ErrMissingParam) + return + } + b := option.checkFunc(cert) + if b { + token, err := GenerateToken(cert) + if err != nil { + WriteError(c, ErrInternalServerError) + return + } + WriteSucc(c, token) + return + } + WriteError(c, ErrRefuseIssueToken) +} diff --git a/go.mod b/go.mod index 78ad918..acf2953 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module nutshttp go 1.17 require ( + github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/gin-gonic/gin v1.7.7 github.com/xujiajun/nutsdb v0.8.0 ) diff --git a/go.sum b/go.sum index 45a5a82..a0d7514 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= diff --git a/response.go b/response.go index 5f5c3fe..0f7ad9b 100644 --- a/response.go +++ b/response.go @@ -17,6 +17,8 @@ var ( ErrBadRequest = APIMessage{Code: 400, Message: "Bad Request"} ErrNotFound = APIMessage{404, "Not Found"} ErrInternalServerError = APIMessage{500, "Internal Server Error"} + ErrMissingParam = APIMessage{400, "Missing Param"} + ErrRefuseIssueToken = APIMessage{400, "Server refused to issue token"} ) type Response struct { From 74fb29b79c94e0982b8b4e4e031d49f94a04df20 Mon Sep 17 00:00:00 2001 From: vaspike Date: Mon, 25 Apr 2022 03:20:50 +0800 Subject: [PATCH 2/5] feat(Auth): Auth module finish&Update Readme --- README.md | 17 ++++++++++++++ auth.go | 57 +++++++++++++++++++++++++++++++++++++++-------- examples/hello.go | 3 ++- http.go | 2 ++ response.go | 2 +- server.go | 3 +++ 6 files changed, 73 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 72c75ec..d1cb6b4 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,20 @@ curl http://localhost:8080/set/bucket001/foo # List all list curl http://localhost:8080/list/bucket001/key1?start=0&end=10 ``` + + +## Auth + +1. Enable Auth: +``` +nutshttp.EnableAuth = true +``` +2. Create Token: +```bash +curl http://127.0.0.1:8080/auth/thisisacert +``` +`thisisacert` replace with your pwd or username +3. Use Token: + +- Add token to HEADERS: + > Authorization : Bearer `` diff --git a/auth.go b/auth.go index 142fd59..167a878 100644 --- a/auth.go +++ b/auth.go @@ -4,6 +4,8 @@ import ( "errors" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" + "log" + "strings" "time" ) @@ -23,7 +25,7 @@ func defaultOptAndCheckFunc() Option { return Option{ ExpireDuration: time.Hour * 4, Issuer: "nutsdb.nutsdb-http", - SigningMethod: jwt.SigningMethodES512, + SigningMethod: jwt.SigningMethodHS256, checkFunc: func(s string) bool { return true }, @@ -31,15 +33,15 @@ func defaultOptAndCheckFunc() Option { } type TokenClaims struct { - Cert string `json:"cert"` + Cert []byte `json:"cert"` jwt.StandardClaims } -var secret = []byte("78") +var secret = []byte("eeeeeettt") func GenerateToken(cert string) (string, error) { claims := TokenClaims{ - cert, + []byte(cert), jwt.StandardClaims{ ExpiresAt: time.Now().Add(option.ExpireDuration).Unix(), Issuer: option.Issuer, @@ -70,11 +72,13 @@ func handler(c *gin.Context) { panic(errors.New("invalid auth option")) } var cert string - err := c.ShouldBind(&cert) - if err != nil { - WriteError(c, ErrMissingParam) - return - } + //err := c.ShouldBind(&cert) + cert = c.Param("cert") + println("cert:", cert) + //if err != nil { + // WriteError(c, ErrMissingParam) + // return + //} b := option.checkFunc(cert) if b { token, err := GenerateToken(cert) @@ -87,3 +91,38 @@ func handler(c *gin.Context) { } WriteError(c, ErrRefuseIssueToken) } + +func (s *NutsHTTPServer) DefaultInitAuth() { + option = defaultOptAndCheckFunc() + sr := s.r.Group("/auth") + sr.GET("/:cert", handler) + s.r.Use(JWTAuthMiddleware()) + log.Println("Auth init succeed") +} + +const Bearer = "Bearer" + +func JWTAuthMiddleware() func(c *gin.Context) { + return func(c *gin.Context) { + authHeader := c.Request.Header.Get("Authorization") + if len(authHeader) == 0 { + WriteError(c, ErrAuthInvalid) + c.Abort() + return + } + parts := strings.SplitN(authHeader, " ", 2) + if !(len(parts) == 2 && parts[0] == Bearer) { + WriteError(c, ErrAuthInvalid) + c.Abort() + return + } + mc, err := CheckToken(parts[1]) + if err != nil { + WriteError(c, ErrAuthInvalid) + c.Abort() + return + } + c.Set("cert", mc.Cert) + c.Next() + } +} diff --git a/examples/hello.go b/examples/hello.go index 6e52042..942a55c 100644 --- a/examples/hello.go +++ b/examples/hello.go @@ -16,7 +16,8 @@ func main() { log.Fatal(err) } defer db.Close() - + // Enable auth + nutshttp.EnableAuth = true go func() { if err := nutshttp.Enable(db); err != nil { panic(err) diff --git a/http.go b/http.go index 0bfad07..335af1d 100644 --- a/http.go +++ b/http.go @@ -4,6 +4,8 @@ import ( "github.com/xujiajun/nutsdb" ) +var EnableAuth bool + func Enable(db *nutsdb.DB) error { s := NewNutsHTTPServer(db) diff --git a/response.go b/response.go index 0f7ad9b..31d1118 100644 --- a/response.go +++ b/response.go @@ -17,8 +17,8 @@ var ( ErrBadRequest = APIMessage{Code: 400, Message: "Bad Request"} ErrNotFound = APIMessage{404, "Not Found"} ErrInternalServerError = APIMessage{500, "Internal Server Error"} - ErrMissingParam = APIMessage{400, "Missing Param"} ErrRefuseIssueToken = APIMessage{400, "Server refused to issue token"} + ErrAuthInvalid = APIMessage{400, "Auth invalid"} ) type Response struct { diff --git a/server.go b/server.go index 11f61b9..5a66c9b 100644 --- a/server.go +++ b/server.go @@ -32,6 +32,9 @@ func (s *NutsHTTPServer) Run(addr string) error { } func (s *NutsHTTPServer) initRouter() { + if EnableAuth { + s.DefaultInitAuth() + } s.initSetRouter() s.initListRouter() From 7d4c212f701d60cee524046acd91b7b8cf9b13c7 Mon Sep 17 00:00:00 2001 From: vaspike Date: Mon, 25 Apr 2022 21:49:23 +0800 Subject: [PATCH 3/5] feat(Auth): Optimize code in auth module --- README.md | 1 + auth.go | 17 +++++++++-------- examples/hello.go | 1 + response.go | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d1cb6b4..8f570d1 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ nutshttp.EnableAuth = true curl http://127.0.0.1:8080/auth/thisisacert ``` `thisisacert` replace with your pwd or username + 3. Use Token: - Add token to HEADERS: diff --git a/auth.go b/auth.go index 167a878..76af496 100644 --- a/auth.go +++ b/auth.go @@ -2,10 +2,13 @@ package nutshttp import ( "errors" + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" - "log" + "strings" + "time" ) @@ -37,7 +40,7 @@ type TokenClaims struct { jwt.StandardClaims } -var secret = []byte("eeeeeettt") +var secret = []byte("3YJM45xgpDkj") func GenerateToken(cert string) (string, error) { claims := TokenClaims{ @@ -72,13 +75,8 @@ func handler(c *gin.Context) { panic(errors.New("invalid auth option")) } var cert string - //err := c.ShouldBind(&cert) cert = c.Param("cert") println("cert:", cert) - //if err != nil { - // WriteError(c, ErrMissingParam) - // return - //} b := option.checkFunc(cert) if b { token, err := GenerateToken(cert) @@ -97,7 +95,10 @@ func (s *NutsHTTPServer) DefaultInitAuth() { sr := s.r.Group("/auth") sr.GET("/:cert", handler) s.r.Use(JWTAuthMiddleware()) - log.Println("Auth init succeed") +} + +func SetSecret(s string) { + secret = []byte(s) } const Bearer = "Bearer" diff --git a/examples/hello.go b/examples/hello.go index 942a55c..16174b9 100644 --- a/examples/hello.go +++ b/examples/hello.go @@ -18,6 +18,7 @@ func main() { defer db.Close() // Enable auth nutshttp.EnableAuth = true + nutshttp.SetSecret("TbI7O6yEdEYa") go func() { if err := nutshttp.Enable(db); err != nil { panic(err) diff --git a/response.go b/response.go index 31d1118..09c0fc9 100644 --- a/response.go +++ b/response.go @@ -18,7 +18,7 @@ var ( ErrNotFound = APIMessage{404, "Not Found"} ErrInternalServerError = APIMessage{500, "Internal Server Error"} ErrRefuseIssueToken = APIMessage{400, "Server refused to issue token"} - ErrAuthInvalid = APIMessage{400, "Auth invalid"} + ErrAuthInvalid = APIMessage{403, "Auth invalid"} ) type Response struct { From 35e09c42fae763cc61ea758d158469bad9ec33e2 Mon Sep 17 00:00:00 2001 From: River Mao Date: Thu, 26 May 2022 21:03:25 +0800 Subject: [PATCH 4/5] feat: Update JWT repo & Secret's original value Update JWT repo from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt` --- auth.go | 11 ++++------- examples/hello.go | 1 - go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/auth.go b/auth.go index 76af496..9b36213 100644 --- a/auth.go +++ b/auth.go @@ -2,14 +2,11 @@ package nutshttp import ( "errors" - - "github.com/dgrijalva/jwt-go" - - "github.com/gin-gonic/gin" - "strings" - "time" + + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt" ) type CheckFunc func(string) bool @@ -40,7 +37,7 @@ type TokenClaims struct { jwt.StandardClaims } -var secret = []byte("3YJM45xgpDkj") +var secret []byte func GenerateToken(cert string) (string, error) { claims := TokenClaims{ diff --git a/examples/hello.go b/examples/hello.go index 16174b9..4716a88 100644 --- a/examples/hello.go +++ b/examples/hello.go @@ -2,7 +2,6 @@ package main import ( "log" - "nutshttp" "github.com/xujiajun/nutsdb" diff --git a/go.mod b/go.mod index acf2953..554e014 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module nutshttp go 1.17 require ( - github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/gin-gonic/gin v1.7.7 + github.com/golang-jwt/jwt v3.2.2+incompatible github.com/xujiajun/nutsdb v0.8.0 ) diff --git a/go.sum b/go.sum index a0d7514..de4886f 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= @@ -22,6 +20,8 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= From aec98b9a72216576be2f230c9e01c90d95241d19 Mon Sep 17 00:00:00 2001 From: vaspike Date: Mon, 6 Jun 2022 13:19:05 +0800 Subject: [PATCH 5/5] style: Remove print statements --- auth.go | 1 - 1 file changed, 1 deletion(-) diff --git a/auth.go b/auth.go index 9b36213..4f9e77a 100644 --- a/auth.go +++ b/auth.go @@ -73,7 +73,6 @@ func handler(c *gin.Context) { } var cert string cert = c.Param("cert") - println("cert:", cert) b := option.checkFunc(cert) if b { token, err := GenerateToken(cert)