• go-kit/kit


    go-kit/kit

    基本功能

    auth -- 校验
    circuitbreaker -- 熔断
    endpoint -- 服务
    log -- 日志
    metrics -- 监控
    ratelimit -- 限流
    sd -- 服务发现
    tracing -- 跟踪
    transport -- 请求

    auth

    
    // basic auth
    // AuthMiddleware returns a Basic Authentication middleware for a particular user and password.
    func AuthMiddleware(requiredUser, requiredPassword, realm string) endpoint.Middleware {
    	requiredUserBytes := toHashSlice([]byte(requiredUser))
    	requiredPasswordBytes := toHashSlice([]byte(requiredPassword))
    
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (interface{}, error) {
    
    			// 获取加密信息
    			auth, ok := ctx.Value(httptransport.ContextKeyRequestAuthorization).(string)
    			if !ok {
    				return nil, AuthError{realm}
    			}
    
    			// 解析用户名及密码
    			givenUser, givenPassword, ok := parseBasicAuth(auth)
    			if !ok {
    				return nil, AuthError{realm}
    			}
    
    			givenUserBytes := toHashSlice(givenUser)
    			givenPasswordBytes := toHashSlice(givenPassword)
    
    			// 判断用户名及密码
    			if subtle.ConstantTimeCompare(givenUserBytes, requiredUserBytes) == 0 ||
    				subtle.ConstantTimeCompare(givenPasswordBytes, requiredPasswordBytes) == 0 {
    				return nil, AuthError{realm}
    			}
    
    			return next(ctx, request)
    		}
    	}
    }
    
    // casbin auth (abac)
    
    // NewEnforcer checks whether the subject is authorized to do the specified
    // action on the given object. If a valid access control model and policy
    // is given, then the generated casbin Enforcer is stored in the context
    // with CasbinEnforcer as the key.
    func NewEnforcer(
    	subject string, object interface{}, action string,
    ) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    			
    			// 模型定义
    			casbinModel := ctx.Value(CasbinModelContextKey)
    
    			// 访问控制策略
    			casbinPolicy := ctx.Value(CasbinPolicyContextKey)
    			enforcer, err := stdcasbin.NewEnforcer(casbinModel, casbinPolicy)
    			if err != nil {
    				return nil, err
    			}
    
    			ctx = context.WithValue(ctx, CasbinEnforcerContextKey, enforcer)
    
    			// 校验 subject,object,action
    			ok, err := enforcer.Enforce(subject, object, action)
    			if err != nil {
    				return nil, err
    			}
    			if !ok {
    				return nil, ErrUnauthorized
    			}
    
    			return next(ctx, request)
    		}
    	}
    }
    
    
    // jwt auth
    
    // NewSigner creates a new JWT token generating middleware, specifying key ID,
    // signing string, signing method and the claims you would like it to contain.
    // Tokens are signed with a Key ID header (kid) which is useful for determining
    // the key to use for parsing. Particularly useful for clients.
    func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    			token := jwt.NewWithClaims(method, claims)
    			token.Header["kid"] = kid
    
    			// Sign and get the complete encoded token as a string using the secret
    			tokenString, err := token.SignedString(key)
    			if err != nil {
    				return nil, err
    			}
    			ctx = context.WithValue(ctx, JWTTokenContextKey, tokenString)
    
    			return next(ctx, request)
    		}
    	}
    }
    
    // NewParser creates a new JWT token parsing middleware, specifying a
    // jwt.Keyfunc interface, the signing method and the claims type to be used. NewParser
    // adds the resulting claims to endpoint context or returns error on invalid token.
    // Particularly useful for servers.
    func NewParser(keyFunc jwt.Keyfunc, method jwt.SigningMethod, newClaims ClaimsFactory) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    			// tokenString is stored in the context from the transport handlers.
    			tokenString, ok := ctx.Value(JWTTokenContextKey).(string)
    			if !ok {
    				return nil, ErrTokenContextMissing
    			}
    
    			// Parse takes the token string and a function for looking up the
    			// key. The latter is especially useful if you use multiple keys
    			// for your application.  The standard is to use 'kid' in the head
    			// of the token to identify which key to use, but the parsed token
    			// (head and claims) is provided to the callback, providing
    			// flexibility.
    			token, err := jwt.ParseWithClaims(tokenString, newClaims(), func(token *jwt.Token) (interface{}, error) {
    				// Don't forget to validate the alg is what you expect:
    				if token.Method != method {
    					return nil, ErrUnexpectedSigningMethod
    				}
    
    				return keyFunc(token)
    			})
    			if err != nil {
    				if e, ok := err.(*jwt.ValidationError); ok {
    					switch {
    					case e.Errors&jwt.ValidationErrorMalformed != 0:
    						// Token is malformed
    						return nil, ErrTokenMalformed
    					case e.Errors&jwt.ValidationErrorExpired != 0:
    						// Token is expired
    						return nil, ErrTokenExpired
    					case e.Errors&jwt.ValidationErrorNotValidYet != 0:
    						// Token is not active yet
    						return nil, ErrTokenNotActive
    					case e.Inner != nil:
    						// report e.Inner
    						return nil, e.Inner
    					}
    					// We have a ValidationError but have no specific Go kit error for it.
    					// Fall through to return original error.
    				}
    				return nil, err
    			}
    
    			if !token.Valid {
    				return nil, ErrTokenInvalid
    			}
    
    			ctx = context.WithValue(ctx, JWTClaimsContextKey, token.Claims)
    
    			return next(ctx, request)
    		}
    	}
    }
    

    circuitbreaker

    func Gobreaker(cb *gobreaker.CircuitBreaker) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (interface{}, error) {
    			return cb.Execute(func() (interface{}, error) { return next(ctx, request) })
    		}
    	}
    }
    
    func HandyBreaker(cb breaker.Breaker) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    			if !cb.Allow() {
    				return nil, breaker.ErrCircuitOpen
    			}
    
    			defer func(begin time.Time) {
    				if err == nil {
    					cb.Success(time.Since(begin))
    				} else {
    					cb.Failure(time.Since(begin))
    				}
    			}(time.Now())
    
    			response, err = next(ctx, request)
    			return
    		}
    	}
    }
    
    func Hystrix(commandName string) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (response interface{}, err error) {
    			var resp interface{}
    			if err := hystrix.Do(commandName, func() (err error) {
    				resp, err = next(ctx, request)
    				return err
    			}, nil); err != nil {
    				return nil, err
    			}
    			return resp, nil
    		}
    	}
    }
    

    ratelimit

    func NewDelayingLimiter(limit Waiter) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (interface{}, error) {
    			if err := limit.Wait(ctx); err != nil {
    				return nil, err
    			}
    			return next(ctx, request)
    		}
    	}
    }
    
    // NewErroringLimiter returns an endpoint.Middleware that acts as a rate
    // limiter. Requests that would exceed the
    // maximum request rate are simply rejected with an error.
    func NewErroringLimiter(limit Allower) endpoint.Middleware {
    	return func(next endpoint.Endpoint) endpoint.Endpoint {
    		return func(ctx context.Context, request interface{}) (interface{}, error) {
    			if !limit.Allow() {
    				return nil, ErrLimited
    			}
    			return next(ctx, request)
    		}
    	}
    }
    
  • 相关阅读:
    抓包工具之Charles
    docker之服务搭建
    Linux之查看开放端口
    Centos7下的开机自启动
    phpredis和predis
    Redis迁移工具之Redis-shake
    服务器间文件实时双向同步(rsync+inotify)
    Linux之轨迹记录(script)
    Redis集群之常用操作
    Redis集群搭建-多服务器
  • 原文地址:https://www.cnblogs.com/SLchuck/p/14499600.html
Copyright © 2020-2023  润新知