李伟乐 2 years ago
parent 1cef450347
commit 2dd0a0002d
  1. 2
      Makefile
  2. 60
      api/user.http.go
  3. 2
      api/user.pb.go
  4. 11
      api/user_http.pb.go
  5. 14
      cmd/gin-kit/main.go
  6. 9
      cmd/kit/main.go
  7. 3
      constants/middleware.go
  8. 37
      example/main.go
  9. 5
      example/service/service.go
  10. 92
      git.diulo.com/mogfee/kit/third_party/auth/auth.pb.go
  11. 2
      go.mod
  12. 4
      go.sum
  13. 57
      internal/token/aes.go
  14. 85
      internal/token/token.go
  15. 18
      internal/token/token_test.go
  16. 14
      internal/xuuid/xuuid.go
  17. 1
      middleware/add_header.go
  18. 28
      middleware/jwt.go
  19. 96
      middleware/jwt/jwt.go
  20. 1
      middleware/logging/logging.go
  21. 2
      third_party/auth/auth.proto

@ -13,6 +13,6 @@ all:
testts:
make ts
gen:
protoc -I ./third_party -I ./proto --ts_out=./api --go_out=./api --go-grpc_out=./api --kit_out=./api --validate_out="lang=go:./api" ./proto/*.proto
protoc -I ./third_party -I ./proto --ts_out=./api --go_out=./api --go-grpc_out=./api --kit_out=./api --gin-kit_out=./api --validate_out="lang=go:./api" ./proto/*.proto
auth:
protoc --go_out=. ./third_party/auth/auth.proto

@ -0,0 +1,60 @@
package user
import (
"git.diulo.com/mogfee/kit/errors"
"git.diulo.com/mogfee/kit/response"
"github.com/gin-gonic/gin"
"context"
"git.diulo.com/mogfee/kit/middleware"
)
func RegisterUserHandler(app *gin.Engine, srv UserServer, m ...middleware.Middleware) {
app.GET("/api/v1/user/list", httpListHandler(srv, m...))
app.POST("/api/v1/user/login", httpLoginHandler(srv, m...))
}
func httpListHandler(srv UserServer, m ...middleware.Middleware) func(c *gin.Context) {
return func(c *gin.Context) {
var post LoginRequest
resp := response.New(c)
if err := resp.BindQuery(&post); err != nil {
resp.Error(err)
return
}
h := func(ctx context.Context, a any) (any, error) {
return srv.List(ctx, a.(*LoginRequest))
}
out, err := middleware.HttpMiddleware(c, h, m...)(c, &post)
if err != nil {
resp.Error(err)
} else {
if v, ok := out.(*LoginResponse); ok {
resp.Success(v)
} else {
resp.Error(errors.InternalServer("RESULT_TYPE_ERROR", "LoginResponse"))
}
}
}
}
func httpLoginHandler(srv UserServer, m ...middleware.Middleware) func(c *gin.Context) {
return func(c *gin.Context) {
var post LoginRequest
resp := response.New(c)
if err := resp.BindJSON(&post); err != nil {
resp.Error(err)
return
}
h := func(ctx context.Context, a any) (any, error) {
return srv.Login(ctx, a.(*LoginRequest))
}
out, err := middleware.HttpMiddleware(c, h, m...)(c, &post)
if err != nil {
resp.Error(err)
} else {
if v, ok := out.(*LoginResponse); ok {
resp.Success(v)
} else {
resp.Error(errors.InternalServer("RESULT_TYPE_ERROR", "LoginResponse"))
}
}
}
}

@ -7,6 +7,7 @@
package user
import (
_ "git.diulo.com/mogfee/kit/third_party/auth"
_ "github.com/envoyproxy/protoc-gen-validate/validate"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
@ -14,7 +15,6 @@ import (
_ "google.golang.org/protobuf/types/descriptorpb"
reflect "reflect"
sync "sync"
_ "third_party/auth"
)
const (

@ -1,8 +1,9 @@
package user
import (
"context"
"git.diulo.com/mogfee/kit/transport/http"
"context"
"git.diulo.com/mogfee/kit/middleware/jwt"
)
type UserHTTPServer interface {
@ -20,6 +21,8 @@ func _User_List0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in LoginRequest
//user:search
var newCtx context.Context = ctx
newCtx = jwt.SetAuthKeyContext(ctx, "user:search")
if err := ctx.BindQuery(&in); err != nil {
return err
}
@ -27,8 +30,7 @@ func _User_List0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context) error {
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.List(ctx, req.(*LoginRequest))
})
out, err := h(ctx, &in)
out, err := h(newCtx, &in)
if err != nil {
return err
}
@ -39,6 +41,7 @@ func _User_List0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context) error {
func _User_Login0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in LoginRequest
var newCtx context.Context = ctx
if err := ctx.Bind(&in); err != nil {
return err
}
@ -46,7 +49,7 @@ func _User_Login0_HTTP_Handler(srv UserHTTPServer) func(ctx http.Context) error
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.Login(ctx, req.(*LoginRequest))
})
out, err := h(ctx, &in)
out, err := h(newCtx, &in)
if err != nil {
return err
}

@ -1,8 +1,11 @@
package main
import (
"fmt"
protogen2 "git.diulo.com/mogfee/kit/protogen"
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/types/descriptorpb"
"strings"
)
func main() {
@ -19,6 +22,15 @@ type Kit struct {
func (u *Kit) addImports(imp string) {
u.imports[imp] = imp
}
func (u *Kit) packageName(f *protogen.File) string {
a := f.Desc.Options().(*descriptorpb.FileOptions)
p := strings.Split(*a.GoPackage, ";")
if len(p) == 2 {
return p[1]
}
return fmt.Sprintf("%s", f.Desc.Name())
}
func (u *Kit) Generate(plugin *protogen.Plugin) error {
if len(plugin.Files) < 1 {
return nil
@ -34,7 +46,7 @@ func (u *Kit) Generate(plugin *protogen.Plugin) error {
}
fname := f.GeneratedFilenamePrefix + ".http.go"
t := plugin.NewGeneratedFile(fname, f.GoImportPath)
t.P("package " + f.Desc.Name())
t.P("package ", u.packageName(f))
t.P("import (")
for _, v := range u.imports {
t.P(`"` + v + `"`)

@ -35,6 +35,7 @@ func (u *Kit) Generate(plugin *protogen.Plugin) error {
return nil
}
u.addImports("context")
u.addImports("git.diulo.com/mogfee/kit/middleware/jwt")
u.addImports("git.diulo.com/mogfee/kit/transport/http")
for _, f := range plugin.Files {
if len(f.Services) == 0 {
@ -84,6 +85,7 @@ func (u *Kit) Generate(plugin *protogen.Plugin) error {
}
func (u *Kit) genGet(f *protogen.File, s *protogen.Service, t *protogen.GeneratedFile, m *protogen.Method) {
autkKey := protogen2.GetAuthKey(m)
method, path := protogen2.GetProtoMethod(m)
if method == "" {
return
@ -94,7 +96,10 @@ func (u *Kit) genGet(f *protogen.File, s *protogen.Service, t *protogen.Generate
var in `, m.Input.GoIdent.GoName)
t.P("//", protogen2.GetAuthKey(m))
t.P(`var newCtx context.Context=ctx`)
if autkKey != "" {
t.P(`newCtx = jwt.SetAuthKeyContext(ctx, "`, autkKey, `")`)
}
if method == protogen2.METHOD_GET {
t.P(`if err := ctx.BindQuery(&in); err != nil {
return err
@ -113,7 +118,7 @@ func (u *Kit) genGet(f *protogen.File, s *protogen.Service, t *protogen.Generate
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.`, m.GoName, `(ctx, req.(*`, m.Input.GoIdent.GoName, `))
})
out, err := h(ctx, &in)
out, err := h(newCtx, &in)
if err != nil {
return err
}

@ -1,4 +1 @@
package constants
type UserIdKey struct {
}

@ -7,6 +7,7 @@ import (
"git.diulo.com/mogfee/kit"
user "git.diulo.com/mogfee/kit/api"
"git.diulo.com/mogfee/kit/example/service"
"git.diulo.com/mogfee/kit/middleware/jwt"
"git.diulo.com/mogfee/kit/middleware/logging"
"git.diulo.com/mogfee/kit/middleware/validate"
"git.diulo.com/mogfee/kit/registry/etcd"
@ -29,23 +30,27 @@ func runApp(host string) {
http.Middleware(
logging.Server(),
validate.Server(),
jwt.JWT(),
),
)
route := hs.Route("/")
route.GET("/", func(ctx http.Context) error {
in := UserAddRequest{Name: "tom"}
http.SetOperation(ctx, "/api/abc")
h := ctx.Middleware(func(ctx context.Context, a any) (any, error) {
return AddUser(ctx, a.(*UserAddRequest))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply, _ := out.(*UserAddResponse)
reply.Id = host
return ctx.Result(200, reply)
})
//route := hs.Route("/")
//route.GET("/", func(ctx http.Context) error {
// in := UserAddRequest{Name: "tom"}
// http.SetOperation(ctx, "/api/abc")
// h := ctx.Middleware(func(ctx context.Context, a any) (any, error) {
// return AddUser(ctx, a.(*UserAddRequest))
// })
// if tr, ok := transport.FromServerContext(ctx); ok {
// fmt.Println(tr.Operation())
// }
// out, err := h(ctx, &in)
// if err != nil {
// return err
// }
// reply, _ := out.(*UserAddResponse)
// reply.Id = host
// return ctx.Result(200, reply)
//})
user.RegisterUserHTTPServer(hs, &service.UserService{})
client, err := clientv3.New(clientv3.Config{
@ -73,6 +78,8 @@ type UserAddResponse struct {
}
func AddUser(ctx context.Context, request *UserAddRequest) (*UserAddResponse, error) {
fmt.Println(jwt.FromUserContext(ctx))
fmt.Println(jwt.FromAuthKeyContext(ctx))
return &UserAddResponse{Id: request.Name}, nil
//errors.New(500, "xx", "")
}

@ -3,7 +3,9 @@ package service
import (
"context"
"encoding/json"
"fmt"
user "git.diulo.com/mogfee/kit/api"
"git.diulo.com/mogfee/kit/middleware/jwt"
"git.diulo.com/mogfee/kit/transport"
)
@ -16,6 +18,9 @@ func (*UserService) Login(ctx context.Context, req *user.LoginRequest) (*user.Lo
return &user.LoginResponse{Token: "182131292"}, nil
}
func (*UserService) List(ctx context.Context, req *user.LoginRequest) (*user.LoginResponse, error) {
fmt.Println(jwt.FromUserContext(ctx))
fmt.Println(jwt.FromAuthKeyContext(ctx))
tr, ok := transport.FromServerContext(ctx)
if ok {
return &user.LoginResponse{Token: tr.Operation()}, nil

@ -0,0 +1,92 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.17.3
// source: third_party/auth/auth.proto
package auth
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
reflect "reflect"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
var file_third_party_auth_auth_proto_extTypes = []protoimpl.ExtensionInfo{
{
ExtendedType: (*descriptorpb.MethodOptions)(nil),
ExtensionType: (*string)(nil),
Field: 1111,
Name: "auth.auth_key",
Tag: "bytes,1111,opt,name=auth_key",
Filename: "third_party/auth/auth.proto",
},
}
// Extension fields to descriptorpb.MethodOptions.
var (
// optional string auth_key = 1111;
E_AuthKey = &file_third_party_auth_auth_proto_extTypes[0]
)
var File_third_party_auth_auth_proto protoreflect.FileDescriptor
var file_third_party_auth_auth_proto_rawDesc = []byte{
0x0a, 0x1b, 0x74, 0x68, 0x69, 0x72, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x2f, 0x61, 0x75,
0x74, 0x68, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x61,
0x75, 0x74, 0x68, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6b, 0x65,
0x79, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x18, 0xd7, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x75, 0x74, 0x68, 0x4b, 0x65,
0x79, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x2e, 0x64, 0x69, 0x75, 0x6c, 0x6f, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x6d, 0x6f, 0x67, 0x66, 0x65, 0x65, 0x2f, 0x6b, 0x69, 0x74, 0x2f, 0x74, 0x68,
0x69, 0x72, 0x64, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var file_third_party_auth_auth_proto_goTypes = []interface{}{
(*descriptorpb.MethodOptions)(nil), // 0: google.protobuf.MethodOptions
}
var file_third_party_auth_auth_proto_depIdxs = []int32{
0, // 0: auth.auth_key:extendee -> google.protobuf.MethodOptions
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
0, // [0:1] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_third_party_auth_auth_proto_init() }
func file_third_party_auth_auth_proto_init() {
if File_third_party_auth_auth_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_third_party_auth_auth_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumExtensions: 1,
NumServices: 0,
},
GoTypes: file_third_party_auth_auth_proto_goTypes,
DependencyIndexes: file_third_party_auth_auth_proto_depIdxs,
ExtensionInfos: file_third_party_auth_auth_proto_extTypes,
}.Build()
File_third_party_auth_auth_proto = out.File
file_third_party_auth_auth_proto_rawDesc = nil
file_third_party_auth_auth_proto_goTypes = nil
file_third_party_auth_auth_proto_depIdxs = nil
}

@ -18,12 +18,14 @@ require (
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0-rc.1 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect

@ -11,6 +11,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
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/envoyproxy/protoc-gen-validate v0.9.1 h1:PS7VIOgmSVhWUEeZwTe7z7zouA22Cr590PzXKbZHOVY=
github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@ -31,6 +33,8 @@ github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MG
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.1 h1:tDQ1LjKga657layZ4JLsRdxgvupebc0xuPwRNuTfUgs=
github.com/golang-jwt/jwt/v5 v5.0.0-rc.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=

@ -0,0 +1,57 @@
package token
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
)
// 加密 aes_128_cbc
func Encrypt(encryptStr string, key []byte, iv string) (string, error) {
encryptBytes := []byte(encryptStr)
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
encryptBytes = pkcs5Padding(encryptBytes, blockSize)
blockMode := cipher.NewCBCEncrypter(block, []byte(iv))
encrypted := make([]byte, len(encryptBytes))
blockMode.CryptBlocks(encrypted, encryptBytes)
return base64.URLEncoding.EncodeToString(encrypted), nil
}
// 解密
func Decrypt(decryptStr string, key []byte, iv string) (string, error) {
decryptBytes, err := base64.URLEncoding.DecodeString(decryptStr)
if err != nil {
return "", err
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
blockMode := cipher.NewCBCDecrypter(block, []byte(iv))
decrypted := make([]byte, len(decryptBytes))
blockMode.CryptBlocks(decrypted, decryptBytes)
decrypted = pkcs5UnPadding(decrypted)
return string(decrypted), nil
}
func pkcs5Padding(cipherText []byte, blockSize int) []byte {
padding := blockSize - len(cipherText)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(cipherText, padText...)
}
func pkcs5UnPadding(decrypted []byte) []byte {
length := len(decrypted)
unPadding := int(decrypted[length-1])
return decrypted[:(length - unPadding)]
}

@ -0,0 +1,85 @@
package token
import (
"encoding/json"
"git.diulo.com/mogfee/kit/errors"
"git.diulo.com/mogfee/kit/internal/xuuid"
"github.com/golang-jwt/jwt/v5"
"time"
)
// iss : jwt签发者
// sub : 主题名称
// aud : 面向的用户,一般都是通过ip或者域名控制
// exp : jwt的有效时间(过期时间),这个有效时间必须要大于签发时间,对于交互接口来说,建议是预设5秒
// nbf : 在什么时候jwt开始生效(在此之前不可用)
// iat : jwt的签发时间
// jti : 唯一标识,主要用来回避被重复使用攻击
type UserInfo struct {
UserId int64
UserName string
UserType string
Permissions []string
UniqueId string
}
func GetToken(key string, info *UserInfo) (token string, uniqId string, err error) {
uniqId = xuuid.UUID()
info.UniqueId = uniqId
var tokenStr string
ctime := time.Now().Unix()
tokenStr, err = jwt.NewWithClaims(jwt.SigningMethodHS256, &jwt.MapClaims{
//jwt签发者
//"iss": "auth.diulo.com",
//主题名称
//"sub": "www.diulo.com",
// 面向的用户,一般都是通过ip或者域名控制
//"aud": "api.diulo.com",
//jwt的有效时间(过期时间),这个有效时间必须要大于签发时间,对于交互接口来说,建议是预设5秒
"exp": ctime + 7200,
//在什么时候jwt开始生效(在此之前不可用)
"nbf": ctime,
//jwt的签发时间
"iat": ctime,
//唯一标识,主要用来回避被重复使用攻击
"jti": uniqId,
"info": info,
}).SignedString([]byte(key))
if err != nil {
return
}
token, err = Encrypt(tokenStr, []byte(key), key)
return
}
func Parse(key string, tokenStr string) (*UserInfo, error) {
if tokenStr == "" {
return nil, errors.Unauthorized("TOKEN_ERROR", "")
}
str, err := Decrypt(tokenStr, []byte(key), key)
if err != nil {
return nil, err
}
token, err := jwt.Parse(str, func(token *jwt.Token) (interface{}, error) {
return []byte(key), nil
})
if err != nil {
return nil, err
}
if token.Valid {
row := struct {
Info *UserInfo
}{}
b, _ := json.Marshal(token.Claims)
if err = json.Unmarshal(b, &row); err != nil {
return nil, err
}
return row.Info, nil
} else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) {
return nil, errors.Unauthorized("TOKEN_EXPIRED", "")
}
return nil, errors.Unauthorized("TOKEN_ERROR", "")
}

@ -0,0 +1,18 @@
package token
import (
"fmt"
"testing"
)
func TestGetToken(t *testing.T) {
tokenKey := "JssLx22bjQwnyqby"
token, uniqId, err := GetToken(tokenKey, &UserInfo{
UserId: 111,
UserType: "admin",
Permissions: []string{"user:search"},
})
fmt.Println(token)
fmt.Println(uniqId, err)
fmt.Println(Parse(tokenKey, token))
}

@ -0,0 +1,14 @@
package xuuid
import (
"github.com/google/uuid"
"strings"
)
func UUID() string {
u, err := uuid.NewUUID()
if err != nil {
return ""
}
return strings.Join(strings.Split(u.String(), "-"), "")
}

@ -17,7 +17,6 @@ func AddHeaderMdMiddle(c *gin.Context) Middleware {
headers["remote_ip"] = []string{c.RemoteIP()}
headers["full_path"] = []string{c.FullPath()}
ctx = metadata.NewIncomingContext(ctx, headers)
return handler(ctx, a)
}
}

@ -1,28 +0,0 @@
package middleware
import (
"context"
"git.diulo.com/mogfee/kit/constants"
"google.golang.org/grpc/metadata"
)
type ValidateUser interface {
ValidateUser(string) (int64, error)
}
func JWT(validate ValidateUser) Middleware {
return func(handler Handler) Handler {
return func(ctx context.Context, a any) (any, error) {
var token string
if md, ok := metadata.FromIncomingContext(ctx); ok {
token = md.Get("token")[0]
}
userId, err := validate.ValidateUser(ctx.Value(token).(string))
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, constants.UserIdKey{}, userId)
return handler(ctx, a)
}
}
}

@ -0,0 +1,96 @@
package jwt
import (
"context"
"git.diulo.com/mogfee/kit/errors"
"git.diulo.com/mogfee/kit/internal/token"
"git.diulo.com/mogfee/kit/middleware"
"git.diulo.com/mogfee/kit/transport"
)
type userIdKey struct{}
type authKey struct {
}
type JwtOption func(o *options)
func WithJwtKey(jwtKey string) JwtOption {
return func(o *options) {
o.jwtKey = jwtKey
}
}
func WithValidate(validate func(authKey string) error) JwtOption {
return func(o *options) {
o.validate = validate
}
}
func WithValidatePermission(validatePermission func(permissions []string, key string) bool) JwtOption {
return func(o *options) {
o.validatePermission = validatePermission
}
}
type options struct {
jwtKey string
validate func(authKey string) error
validatePermission func(validatePermission []string, key string) bool
}
func JWT(opts ...JwtOption) middleware.Middleware {
var cfg = &options{
jwtKey: "JssLx22bjQwnyqby",
validatePermission: InSlice,
}
for _, o := range opts {
o(cfg)
}
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, a any) (any, error) {
var tokenStr string
if tr, ok := transport.FromServerContext(ctx); ok {
tokenStr = tr.RequestHeader().Get("token")
}
userInfo, err := token.Parse(cfg.jwtKey, tokenStr)
if err != nil {
return nil, err
}
permission := FromAuthKeyContext(ctx)
if permission != "" {
if !cfg.validatePermission(userInfo.Permissions, permission) {
return nil, errors.Unauthorized("TOKEN_PERMISSION_BAD", "")
}
}
if cfg.validate != nil {
if err = cfg.validate(userInfo.UniqueId); err != nil {
return nil, err
}
}
ctx = SetUserContext(ctx, userInfo)
return handler(ctx, a)
}
}
}
func InSlice(validatePermission []string, key string) bool {
for _, e := range validatePermission {
if e == key {
return true
}
}
return false
}
func SetUserContext(ctx context.Context, user *token.UserInfo) context.Context {
return context.WithValue(ctx, userIdKey{}, user)
}
func FromUserContext(ctx context.Context) (user *token.UserInfo, ok bool) {
user, ok = ctx.Value(userIdKey{}).(*token.UserInfo)
return
}
func SetAuthKeyContext(ctx context.Context, key string) context.Context {
return context.WithValue(ctx, authKey{}, key)
}
func FromAuthKeyContext(ctx context.Context) string {
return ctx.Value(authKey{}).(string)
}

@ -8,6 +8,7 @@ import (
func Server() middleware.Middleware {
return func(handler middleware.Handler) middleware.Handler {
return func(ctx context.Context, a any) (any, error) {
ctx = context.WithValue(ctx, "user-id", "1111")
return handler(ctx, a)
}
}

@ -1,6 +1,6 @@
syntax = "proto3";
package auth;
option go_package = "third_party/auth;auth";
option go_package = "git.diulo.com/mogfee/kit/third_party/auth";
import "google/protobuf/descriptor.proto";

Loading…
Cancel
Save