我对go-kit和微服务架构也很陌生。
我有一个JWT,其中包含经过身份验证的用户ID作为声明,以及每个服务的方法,我想检查用户是否有权更新自己的客户端记录,但似乎无处不在我说,感觉不对。做这样的事情的最佳做法是什么?
// client.go
type Client struct {
ID string `json:"id"`
UserID string `json:"user_id"`
// ...
}
type ClientDataLayer interface {
Load(db *sql.DB, id string) *Client
Update(db *sql.DB, cl *Client) *Client
// ... more CRUD methods
}
在服务中间件中执行此操作我将不得不调用另一个服务的方法,这似乎打破了体系结构的目的:
// service.go
type Service interface {
UpdateClient(ctx context.Context, cl *Client) (*Client, error)
// ... more methods
}
func NewClientService(db *sql.DB, cdl ClientDataLayer) {
// ....
}
type service struct {
db *sql.DB
cdl ClientDataLayer
}
func (svc *service) UpdateClient(ctx context.Context, id string) (*Client, error) {
return nil, nil
}
// service middleware
type accessControl struct {
svc Service
}
func (ac *accessControl) UpdateClient(ctx context.Context, cl *Client) (*Client, error) {
// ... get token and claims from context
// scopes := jwt.Claims().Get("scopes")
// Here I don't have the client's user_id,
// and it does not feel right to call another service's method
if !strings.Contains(scopes, "client:write") || cl.UserID != userID {
return nil, errors.New("forbidden")
}
// ...
return nil, nil
}
在端点上执行它几乎相同的
// transport.go
func makeUpdateClientEndpoint(svc Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
// type cast request
// ... get token and claims from context
// scopes := jwt.Claims().Get("scopes")
// Same problem as before, I don't have the client's user_id
if !strings.Contains(scopes, "client:write") || cl.UserID != userID {
return nil, errors.New("forbidden")
}
cl, _ := svc.UpdateClient(ctx, request.ClientID)
// ...
return nil, nil
}
}
我可能会通过使用ClientDataLayer来检索客户端并检查用户的ID。作为一种避免混淆另一种服务方法来加载客户端的方法,因为它可能还有用于日志记录或度量的中间件。
我怎么能在没有那么多麻烦的情况下实现这一目标?我想打破模式?