From a326dfea6d053a502c4585a81ab526738f168753 Mon Sep 17 00:00:00 2001 From: nannan00 <17491932+nannan00@users.noreply.github.com> Date: Thu, 6 Feb 2025 11:42:44 +0800 Subject: [PATCH 1/2] fix: api request - access_key_id_not_match_app_code --- src/bkauth/pkg/api/app/handler/access_key.go | 38 ++++++------- .../pkg/api/app/handler/access_key_slz.go | 11 +--- src/bkauth/pkg/api/app/router.go | 15 ++++-- src/bkauth/pkg/api/common/middleware.go | 34 +++++++++++- src/bkauth/pkg/api/common/slz.go | 13 +++-- src/bkauth/pkg/database/dao/access_key.go | 17 +++++- .../pkg/database/dao/access_key_test.go | 19 ++++++- .../pkg/database/dao/mock/access_key.go | 18 ++++++- src/bkauth/pkg/database/dao/mock/app.go | 3 +- src/bkauth/pkg/database/dao/mock/oauth_app.go | 3 +- src/bkauth/pkg/database/dao/mock/scope.go | 3 +- src/bkauth/pkg/database/dao/mock/target.go | 3 +- src/bkauth/pkg/service/access_key.go | 40 +++++++++----- src/bkauth/pkg/service/access_key_test.go | 54 ++++++++++++++++++- src/bkauth/pkg/service/mock/access_key.go | 18 ++++++- src/bkauth/pkg/service/mock/app.go | 3 +- src/bkauth/pkg/service/mock/oauth_app.go | 3 +- src/bkauth/pkg/service/mock/scope.go | 3 +- src/bkauth/pkg/service/mock/target.go | 3 +- 19 files changed, 223 insertions(+), 78 deletions(-) diff --git a/src/bkauth/pkg/api/app/handler/access_key.go b/src/bkauth/pkg/api/app/handler/access_key.go index fdb119c..29c07db 100644 --- a/src/bkauth/pkg/api/app/handler/access_key.go +++ b/src/bkauth/pkg/api/app/handler/access_key.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -45,11 +45,11 @@ import ( func CreateAccessKey(c *gin.Context) { errorWrapf := errorx.NewLayerFunctionErrorWrapf("Handler", "CreateAccessKey") - // NOTE: 通过API创建, 不支持指定app_secret + // NOTE: 通过 API 创建,不支持指定 app_secret createdSource := util.GetAccessAppCode(c) - // TODO: 统一考虑,如何避免获取URL参数的代码重复 - // 获取URL参数 + // TODO: 统一考虑,如何避免获取 URL 参数的代码重复 + // 获取 URL 参数 var uriParams common.AppCodeSerializer if err := c.ShouldBindUri(&uriParams); err != nil { util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) @@ -57,7 +57,7 @@ func CreateAccessKey(c *gin.Context) { } appCode := uriParams.AppCode - // 创建Secret + // 创建 Secret svc := service.NewAccessKeyService() accessKey, err := svc.Create(appCode, createdSource) if err != nil { @@ -73,7 +73,7 @@ func CreateAccessKey(c *gin.Context) { return } - // 缓存里删除appCode的所有Secret + // 缓存里删除 appCode 的所有 Secret cacheImpls.DeleteAccessKey(appCode) util.SuccessJSONResponse(c, "ok", accessKey) @@ -96,10 +96,10 @@ func CreateAccessKey(c *gin.Context) { func DeleteAccessKey(c *gin.Context) { errorWrapf := errorx.NewLayerFunctionErrorWrapf("Handler", "DeleteAccessKey") - // TODO: 校验secret创建来源与删除来源是否一致,只有创建者才可以删除???目前只有PaaS可以管理,即增删 + // TODO: 校验 secret 创建来源与删除来源是否一致,只有创建者才可以删除???目前只有 PaaS 可以管理,即增删 // source := util.GetAccessAppCode(c) - var uriParams accessKeyAndAppSerializer + var uriParams common.AccessKeyAndAppCodeSerializer if err := c.ShouldBindUri(&uriParams); err != nil { util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) return @@ -107,7 +107,7 @@ func DeleteAccessKey(c *gin.Context) { appCode := uriParams.AppCode accessKeyID := uriParams.AccessKeyID - // 删除Secret + // 删除 Secret svc := service.NewAccessKeyService() err := svc.DeleteByID(appCode, accessKeyID) if err != nil { @@ -123,7 +123,7 @@ func DeleteAccessKey(c *gin.Context) { return } - // 缓存里删除appCode的所有Secret + // 缓存里删除 appCode 的所有 Secret cacheImpls.DeleteAccessKey(appCode) util.SuccessJSONResponse(c, "ok", nil) @@ -143,7 +143,7 @@ func DeleteAccessKey(c *gin.Context) { // @Header 200 {string} X-Request-Id "the request id" // @Router /api/v1/apps/{bk_app_code}/access-keys [get] func ListAccessKey(c *gin.Context) { - // 获取URL参数 + // 获取 URL 参数 var uriParams common.AppCodeSerializer if err := c.ShouldBindUri(&uriParams); err != nil { util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) @@ -151,7 +151,7 @@ func ListAccessKey(c *gin.Context) { } appCode := uriParams.AppCode - // 创建Secret + // 创建 Secret svc := service.NewAccessKeyService() accessKeys, err := svc.ListWithCreatedAtByAppCode(appCode) if err != nil { @@ -178,7 +178,7 @@ func ListAccessKey(c *gin.Context) { // @Header 200 {string} X-Request-Id "the request id" // @Router /api/v1/apps/{bk_app_code}/access-keys/verify [post] func VerifyAccessKey(c *gin.Context) { - // 获取URL参数 + // 获取 URL 参数 var uriParams common.AppCodeSerializer if err := c.ShouldBindUri(&uriParams); err != nil { util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) @@ -202,7 +202,7 @@ func VerifyAccessKey(c *gin.Context) { data := gin.H{"is_match": exists} if !exists { - // Note: 这里校验不通过,是业务逻辑,并非接口通讯的认证和鉴权,所以不能返回 401或403 状态码 + // Note: 这里校验不通过,是业务逻辑,并非接口通讯的认证和鉴权,所以不能返回 401 或 403 状态码 util.SuccessJSONResponse(c, "bk_app_code or bk_app_secret invalid", data) return } @@ -227,8 +227,8 @@ func VerifyAccessKey(c *gin.Context) { // @Router /api/v1/apps/{bk_app_code}/access-keys/{access_key_id} [put] func UpdateAccessKey(c *gin.Context) { errorWrapf := errorx.NewLayerFunctionErrorWrapf("Handler", "PutAccessKey") - // 获取URL参数 - var uriParams accessKeyAndAppSerializer + // 获取 URL 参数 + var uriParams common.AccessKeyAndAppCodeSerializer if err := c.ShouldBindUri(&uriParams); err != nil { util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) return @@ -243,9 +243,9 @@ func UpdateAccessKey(c *gin.Context) { return } - // 更新accessKey + // 更新 accessKey - // 获取更新的updateFiledMap:如果是空则不更新 + // 获取更新的 updateFiledMap:如果是空则不更新 var updateFiledMap map[string]interface{} err := mapstructure.Decode(body, &updateFiledMap) if err != nil { @@ -267,7 +267,7 @@ func UpdateAccessKey(c *gin.Context) { return } - // 缓存里删除appCode的所有Secret + // 缓存里删除 appCode 的所有 Secret _ = cacheImpls.DeleteAccessKey(uriParams.AppCode) util.SuccessJSONResponse(c, "ok", nil) diff --git a/src/bkauth/pkg/api/app/handler/access_key_slz.go b/src/bkauth/pkg/api/app/handler/access_key_slz.go index ef0d793..40c93e0 100644 --- a/src/bkauth/pkg/api/app/handler/access_key_slz.go +++ b/src/bkauth/pkg/api/app/handler/access_key_slz.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -18,19 +18,10 @@ package handler -import ( - "bkauth/pkg/api/common" -) - type appSecretSerializer struct { AppSecret string `json:"bk_app_secret" binding:"required,max=128" example:"bk_paas"` } -type accessKeyAndAppSerializer struct { - common.AppCodeSerializer - AccessKeyID int64 `uri:"access_key_id" binding:"required" example:"1"` -} - type accessKeyUpdateSerializer struct { Enabled *bool `json:"enabled" binding:"required" example:"true" mapstructure:"enabled,omitempty"` } diff --git a/src/bkauth/pkg/api/app/router.go b/src/bkauth/pkg/api/app/router.go index 9a0c84c..d646cfb 100644 --- a/src/bkauth/pkg/api/app/router.go +++ b/src/bkauth/pkg/api/app/router.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -21,8 +21,8 @@ package app import ( "github.com/gin-gonic/gin" - handler "bkauth/pkg/api/app/handler" - common "bkauth/pkg/api/common" + "bkauth/pkg/api/app/handler" + "bkauth/pkg/api/common" ) // Register ... @@ -39,8 +39,13 @@ func Register(r *gin.RouterGroup) { { // AccessKey CURD for PaaS accessKeyCURD.POST("", handler.CreateAccessKey) - accessKeyCURD.DELETE("/:access_key_id", handler.DeleteAccessKey) - accessKeyCURD.PUT("/:access_key_id", handler.UpdateAccessKey) + accessKeyUD := accessKeyCURD.Group("/:access_key_id") + accessKeyUD.Use(common.AccessKeyExists()) + { + accessKeyUD.DELETE("", handler.DeleteAccessKey) + accessKeyUD.PUT("", handler.UpdateAccessKey) + } + } // List for PaaS/APIGateway diff --git a/src/bkauth/pkg/api/common/middleware.go b/src/bkauth/pkg/api/common/middleware.go index 0b0d964..c3e2f40 100644 --- a/src/bkauth/pkg/api/common/middleware.go +++ b/src/bkauth/pkg/api/common/middleware.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -57,6 +57,36 @@ func AppCodeExists() gin.HandlerFunc { } } +func AccessKeyExists() gin.HandlerFunc { + return func(c *gin.Context) { + var uriParams AccessKeyAndAppCodeSerializer + if err := c.ShouldBindUri(&uriParams); err != nil { + util.BadRequestErrorJSONResponse(c, util.ValidationErrorMessage(err)) + c.Abort() + return + } + + appCode := uriParams.AppCode + accessKeyID := uriParams.AccessKeyID + + // check access_key exists + exists, err := service.NewAccessKeyService().ExistsByAppCodeAndID(appCode, accessKeyID) + if err != nil { + util.SystemErrorJSONResponse(c, fmt.Errorf("query access_key_id(%d) of app(%s) fail, error: %w", accessKeyID, appCode, err)) + c.Abort() + return + } + + if !exists { + util.NotFoundJSONResponse(c, fmt.Sprintf("AccessKeyID(%d) of app(%s) not exists", accessKeyID, appCode)) + c.Abort() + return + } + + c.Next() + } +} + func NewAPIAllowMiddleware(api string) gin.HandlerFunc { return func(c *gin.Context) { accessAppCode := util.GetAccessAppCode(c) @@ -79,7 +109,7 @@ func TargetExistsAndClientValid() gin.HandlerFunc { } targetID := uriParams.TargetID - // Note: 这里没必要缓存,因为本身Target的注册和变更频率很低 + // Note: 这里没必要缓存,因为本身 Target 的注册和变更频率很低 svc := service.NewTargetService() target, err := svc.Get(targetID) if err != nil { diff --git a/src/bkauth/pkg/api/common/slz.go b/src/bkauth/pkg/api/common/slz.go index 0494a8a..515b0ce 100644 --- a/src/bkauth/pkg/api/common/slz.go +++ b/src/bkauth/pkg/api/common/slz.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -24,7 +24,7 @@ import ( ) var ( - // ValidAppCodeRegex 小写字母或数字开头, 可以包含小写字母/数字/下划线/连字符 + // ValidAppCodeRegex 小写字母或数字开头,可以包含小写字母/数字/下划线/连字符 ValidAppCodeRegex = regexp.MustCompile("^[a-z0-9][a-z0-9_-]{0,31}$") ErrInvalidAppCode = errors.New("invalid app_code: app_code should begin with a lowercase letter or numbers, " + @@ -35,9 +35,14 @@ type AppCodeSerializer struct { AppCode string `uri:"bk_app_code" json:"bk_app_code" binding:"required,min=1,max=32" example:"bk_paas"` } +type AccessKeyAndAppCodeSerializer struct { + AppCodeSerializer + AccessKeyID int64 `uri:"access_key_id" binding:"required" example:"1"` +} + func (s *AppCodeSerializer) ValidateAppCode() error { - // app_code的规则是: - // 由小写英文字母、连接符(-)、下划线(_)或数字组成,长度为[1~32]个字符, 并且以字母或数字开头 (^[a-z0-9][a-z0-9_-]{0,31}$) + // app_code 的规则是: + // 由小写英文字母、连接符 (-)、下划线 (_) 或数字组成,长度为 [1~32] 个字符,并且以字母或数字开头 (^[a-z0-9][a-z0-9_-]{0,31}$) if !ValidAppCodeRegex.MatchString(s.AppCode) { return ErrInvalidAppCode } diff --git a/src/bkauth/pkg/database/dao/access_key.go b/src/bkauth/pkg/database/dao/access_key.go index 6c342f3..9cb3022 100644 --- a/src/bkauth/pkg/database/dao/access_key.go +++ b/src/bkauth/pkg/database/dao/access_key.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -55,6 +55,7 @@ type AccessKeyManager interface { Count(appCode string) (int64, error) ListAccessKeyByAppCode(appCode string) ([]AccessKey, error) List() ([]AccessKey, error) + ExistsByAppCodeAndID(appCode string, id int64) (bool, error) } type accessKeyManager struct { @@ -191,3 +192,17 @@ func (m *accessKeyManager) List() (accessKeys []AccessKey, err error) { } return } + +func (m *accessKeyManager) ExistsByAppCodeAndID(appCode string, id int64) (bool, error) { + var existingID int64 + query := `SELECT id FROM access_key WHERE app_code = ? AND id = ? LIMIT 1` + err := database.SqlxGet(m.DB, &existingID, query, appCode, id) + if errors.Is(err, sql.ErrNoRows) { + return false, nil + } + if err != nil { + return false, err + } + + return true, nil +} diff --git a/src/bkauth/pkg/database/dao/access_key_test.go b/src/bkauth/pkg/database/dao/access_key_test.go index 8e12d00..ee9e95e 100644 --- a/src/bkauth/pkg/database/dao/access_key_test.go +++ b/src/bkauth/pkg/database/dao/access_key_test.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -22,7 +22,7 @@ import ( "testing" "time" - sqlmock "github.com/DATA-DOG/go-sqlmock" + "github.com/DATA-DOG/go-sqlmock" "github.com/jmoiron/sqlx" "github.com/stretchr/testify/assert" @@ -180,3 +180,18 @@ func Test_ListAccessKeyByAppCode(t *testing.T) { assert.Len(t, accessKeys, 2) }) } + +func Test_ExistsByAppCodeAndID(t *testing.T) { + database.RunWithMock(t, func(db *sqlx.DB, mock sqlmock.Sqlmock, t *testing.T) { + mockQuery := `^SELECT id FROM access_key WHERE app_code = (.*) AND id = (.*) LIMIT 1$` + mockRows := sqlmock.NewRows([]string{"id"}).AddRow(int64(1)) + mock.ExpectQuery(mockQuery).WithArgs("bkauth", int64(1)).WillReturnRows(mockRows) + + manager := &accessKeyManager{DB: db} + + exists, err := manager.ExistsByAppCodeAndID("bkauth", 1) + + assert.NoError(t, err, "query from db fail.") + assert.Equal(t, exists, true) + }) +} diff --git a/src/bkauth/pkg/database/dao/mock/access_key.go b/src/bkauth/pkg/database/dao/mock/access_key.go index eea1ebe..2e898db 100644 --- a/src/bkauth/pkg/database/dao/mock/access_key.go +++ b/src/bkauth/pkg/database/dao/mock/access_key.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/database/dao" - + dao "bkauth/pkg/database/dao" reflect "reflect" gomock "github.com/golang/mock/gomock" @@ -111,6 +110,21 @@ func (mr *MockAccessKeyManagerMockRecorder) Exists(appCode, appSecret interface{ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockAccessKeyManager)(nil).Exists), appCode, appSecret) } +// ExistsByAppCodeAndID mocks base method. +func (m *MockAccessKeyManager) ExistsByAppCodeAndID(appCode string, id int64) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistsByAppCodeAndID", appCode, id) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExistsByAppCodeAndID indicates an expected call of ExistsByAppCodeAndID. +func (mr *MockAccessKeyManagerMockRecorder) ExistsByAppCodeAndID(appCode, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsByAppCodeAndID", reflect.TypeOf((*MockAccessKeyManager)(nil).ExistsByAppCodeAndID), appCode, id) +} + // List mocks base method. func (m *MockAccessKeyManager) List() ([]dao.AccessKey, error) { m.ctrl.T.Helper() diff --git a/src/bkauth/pkg/database/dao/mock/app.go b/src/bkauth/pkg/database/dao/mock/app.go index 9febe58..d3b4e49 100644 --- a/src/bkauth/pkg/database/dao/mock/app.go +++ b/src/bkauth/pkg/database/dao/mock/app.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/database/dao" - + dao "bkauth/pkg/database/dao" reflect "reflect" gomock "github.com/golang/mock/gomock" diff --git a/src/bkauth/pkg/database/dao/mock/oauth_app.go b/src/bkauth/pkg/database/dao/mock/oauth_app.go index d7f555c..a88e779 100644 --- a/src/bkauth/pkg/database/dao/mock/oauth_app.go +++ b/src/bkauth/pkg/database/dao/mock/oauth_app.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/database/dao" - + dao "bkauth/pkg/database/dao" reflect "reflect" gomock "github.com/golang/mock/gomock" diff --git a/src/bkauth/pkg/database/dao/mock/scope.go b/src/bkauth/pkg/database/dao/mock/scope.go index 13abc89..da70b9c 100644 --- a/src/bkauth/pkg/database/dao/mock/scope.go +++ b/src/bkauth/pkg/database/dao/mock/scope.go @@ -5,10 +5,9 @@ package mock import ( + dao "bkauth/pkg/database/dao" reflect "reflect" - "bkauth/pkg/database/dao" - gomock "github.com/golang/mock/gomock" ) diff --git a/src/bkauth/pkg/database/dao/mock/target.go b/src/bkauth/pkg/database/dao/mock/target.go index ece1222..fa4446f 100644 --- a/src/bkauth/pkg/database/dao/mock/target.go +++ b/src/bkauth/pkg/database/dao/mock/target.go @@ -5,10 +5,9 @@ package mock import ( + dao "bkauth/pkg/database/dao" reflect "reflect" - "bkauth/pkg/database/dao" - gomock "github.com/golang/mock/gomock" ) diff --git a/src/bkauth/pkg/service/access_key.go b/src/bkauth/pkg/service/access_key.go index a8a27c4..5129902 100644 --- a/src/bkauth/pkg/service/access_key.go +++ b/src/bkauth/pkg/service/access_key.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -32,9 +32,9 @@ import ( const ( AccessKeySVC = "AccessKeySVC" - // MaxSecretsPreApp 每个App最多有2个secret + // MaxSecretsPreApp 每个 App 最多有 2 个 secret MaxSecretsPreApp = 2 - // MinSecretsPreApp 每个App至少有一个secret + // MinSecretsPreApp 每个 App 至少有一个 secret MinSecretsPreApp = 1 ) @@ -47,6 +47,7 @@ type AccessKeyService interface { Verify(appCode, appSecret string) (bool, error) ListEncryptedAccessKeyByAppCode(appCode string) (appSecrets []types.AccessKey, err error) List() ([]types.AccessKey, error) + ExistsByAppCodeAndID(appCode string, id int64) (bool, error) } type accessKeyService struct { @@ -59,18 +60,18 @@ func NewAccessKeyService() AccessKeyService { } } -// Create : 创建应用密钥,createdSource为创建来源,即哪个系统创建的 +// Create : 创建应用密钥,createdSource 为创建来源,即哪个系统创建的 func (s *accessKeyService) Create(appCode, createdSource string) (accessKey types.AccessKey, err error) { errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "Create") // 数量的保证是业务上的一个基础逻辑 - // Note: 这里没有处理并发问题导致创建超过2个的问题,因为多创建了也没有太多影响 + // Note: 这里没有处理并发问题导致创建超过 2 个的问题,因为多创建了也没有太多影响 count, err := s.manager.Count(appCode) if err != nil { return accessKey, errorWrapf(err, "manager.Count appCode=`%s` fail", appCode) } if count >= MaxSecretsPreApp { - // Note: 这里不能使用errorWrapf,否则上层无法判断错误是系统错误还是校验不通过 + // Note: 这里不能使用 errorWrapf,否则上层无法判断错误是系统错误还是校验不通过 err = util.ValidationErrorWrap( fmt.Errorf("app(%s) can only have %d secrets, [current %d]", appCode, MaxSecretsPreApp, count)) return accessKey, err @@ -101,7 +102,7 @@ func (s *accessKeyService) Create(appCode, createdSource string) (accessKey type return } -// CreateWithSecret : 创建应用密钥,支持指定appSecret的值,createdSource为创建来源,即哪个系统创建的 +// CreateWithSecret : 创建应用密钥,支持指定 appSecret 的值,createdSource 为创建来源,即哪个系统创建的 func (s *accessKeyService) CreateWithSecret(appCode, appSecret, createdSource string) (err error) { errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "CreateWithSecret") @@ -117,11 +118,11 @@ func (s *accessKeyService) CreateWithSecret(appCode, appSecret, createdSource st func (s *accessKeyService) DeleteByID(appCode string, id int64) (err error) { errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "DeleteByID") - // 只剩下唯一一个Secret,则无法删除 - // TODO: 这里没有处理并发问题可能会导致一个App没有任何一个Secret,进而导致App无法调用任何蓝鲸API + // 只剩下唯一一个 Secret,则无法删除 + // TODO: 这里没有处理并发问题可能会导致一个 App 没有任何一个 Secret,进而导致 App 无法调用任何蓝鲸 API // Note: 乐观锁只能解决查询和修改的数据是相同的问题,这里是查询数量,并修改其中一条,乐观锁应该无法很好解决 - // 可以使用 select_for_update 之类的悲观锁, 或引入全局锁,如Redis分布式锁解决这个问题 - // 但目前没有这个必要,因为管理Secret的行为是在PaaS端,可以让用户删除时,明确输入要删除的Secret做确认 + // 可以使用 select_for_update 之类的悲观锁,或引入全局锁,如 Redis 分布式锁解决这个问题 + // 但目前没有这个必要,因为管理 Secret 的行为是在 PaaS 端,可以让用户删除时,明确输入要删除的 Secret 做确认 count, err := s.manager.Count(appCode) if err != nil { return errorWrapf(err, "manager.Count appCode=`%s` fail", appCode) @@ -131,7 +132,7 @@ func (s *accessKeyService) DeleteByID(appCode string, id int64) (err error) { fmt.Errorf("app(%s) have %d secret at least, [current %d]", appCode, MinSecretsPreApp, count)) } - // 防御性,避免误删除Secret,所以需要额外AppCode来二次保证 + // 防御性,避免误删除 Secret,所以需要额外 AppCode 来二次保证 _, err = s.manager.DeleteByID(appCode, id) if err != nil { return errorWrapf(err, "manager.DeleteByID appCode=`%s` id=`%d` fail", appCode, id) @@ -140,7 +141,7 @@ func (s *accessKeyService) DeleteByID(appCode string, id int64) (err error) { return } -// UpdateByID 更新accessKey +// UpdateByID 更新 accessKey func (s *accessKeyService) UpdateByID(id int64, updateFiledMap map[string]interface{}) (err error) { errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "UpdateByID") _, err = s.manager.UpdateByID(id, updateFiledMap) @@ -190,7 +191,7 @@ func (s *accessKeyService) ListWithCreatedAtByAppCode(appCode string) ( func (s *accessKeyService) Verify(appCode, appSecret string) (exists bool, err error) { errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "Verify") - // DB里存储的是加密后的密钥,需要对即将校验的Secret加密后查询 + // DB 里存储的是加密后的密钥,需要对即将校验的 Secret 加密后查询 encryptedAppSecret := ConvertToEncryptedAppSecret(appSecret) exists, err = s.manager.Exists(appCode, encryptedAppSecret) @@ -244,3 +245,14 @@ func (s *accessKeyService) List() (accessKeys []types.AccessKey, err error) { return } + +func (s *accessKeyService) ExistsByAppCodeAndID(appCode string, id int64) (bool, error) { + errorWrapf := errorx.NewLayerFunctionErrorWrapf(AccessKeySVC, "ExistsByAppCodeAndID") + + exists, err := s.manager.ExistsByAppCodeAndID(appCode, id) + if err != nil { + return exists, errorWrapf(err, "manager.ExistsByAppCodeAndID appCode=`%s` id=`%d` fail", appCode, id) + } + + return exists, nil +} diff --git a/src/bkauth/pkg/service/access_key_test.go b/src/bkauth/pkg/service/access_key_test.go index 32cea80..43743bd 100644 --- a/src/bkauth/pkg/service/access_key_test.go +++ b/src/bkauth/pkg/service/access_key_test.go @@ -1,6 +1,6 @@ /* * TencentBlueKing is pleased to support the open source community by making - * 蓝鲸智云 - Auth服务(BlueKing - Auth) available. + * 蓝鲸智云 - Auth 服务 (BlueKing - Auth) available. * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. * Licensed under the MIT License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at @@ -19,6 +19,8 @@ package service import ( + "fmt" + "github.com/golang/mock/gomock" . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" @@ -51,3 +53,53 @@ var _ = Describe("accessKeyService", func() { }) }) }) + +var _ = Describe("accessKeyService", func() { + Describe("ExistsByAppCodeAndID cases", func() { + var ctl *gomock.Controller + + BeforeEach(func() { + ctl = gomock.NewController(GinkgoT()) + }) + + AfterEach(func() { + ctl.Finish() + }) + + It("exists", func() { + mockAppKeyManager := mock.NewMockAccessKeyManager(ctl) + mockAppKeyManager.EXPECT().ExistsByAppCodeAndID("testApp", int64(1)).Return(true, nil) + + svc := accessKeyService{ + manager: mockAppKeyManager, + } + exists, err := svc.ExistsByAppCodeAndID("testApp", 1) + assert.NoError(GinkgoT(), err) + assert.True(GinkgoT(), exists) + }) + + It("does not exist", func() { + mockAppKeyManager := mock.NewMockAccessKeyManager(ctl) + mockAppKeyManager.EXPECT().ExistsByAppCodeAndID("testApp", int64(1)).Return(false, nil) + + svc := accessKeyService{ + manager: mockAppKeyManager, + } + exists, err := svc.ExistsByAppCodeAndID("testApp", 1) + assert.NoError(GinkgoT(), err) + assert.False(GinkgoT(), exists) + }) + + It("error", func() { + mockAppKeyManager := mock.NewMockAccessKeyManager(ctl) + mockAppKeyManager.EXPECT().ExistsByAppCodeAndID("testApp", int64(1)).Return(false, fmt.Errorf("some error")) + + svc := accessKeyService{ + manager: mockAppKeyManager, + } + exists, err := svc.ExistsByAppCodeAndID("testApp", 1) + assert.Error(GinkgoT(), err) + assert.False(GinkgoT(), exists) + }) + }) +}) diff --git a/src/bkauth/pkg/service/mock/access_key.go b/src/bkauth/pkg/service/mock/access_key.go index 7a6c449..5265c15 100644 --- a/src/bkauth/pkg/service/mock/access_key.go +++ b/src/bkauth/pkg/service/mock/access_key.go @@ -5,10 +5,9 @@ package mock import ( + types "bkauth/pkg/service/types" reflect "reflect" - "bkauth/pkg/service/types" - gomock "github.com/golang/mock/gomock" ) @@ -78,6 +77,21 @@ func (mr *MockAccessKeyServiceMockRecorder) DeleteByID(appCode, id interface{}) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByID", reflect.TypeOf((*MockAccessKeyService)(nil).DeleteByID), appCode, id) } +// ExistsByAppCodeAndID mocks base method. +func (m *MockAccessKeyService) ExistsByAppCodeAndID(appCode string, id int64) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExistsByAppCodeAndID", appCode, id) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExistsByAppCodeAndID indicates an expected call of ExistsByAppCodeAndID. +func (mr *MockAccessKeyServiceMockRecorder) ExistsByAppCodeAndID(appCode, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExistsByAppCodeAndID", reflect.TypeOf((*MockAccessKeyService)(nil).ExistsByAppCodeAndID), appCode, id) +} + // List mocks base method. func (m *MockAccessKeyService) List() ([]types.AccessKey, error) { m.ctrl.T.Helper() diff --git a/src/bkauth/pkg/service/mock/app.go b/src/bkauth/pkg/service/mock/app.go index 8f82df4..cfab245 100644 --- a/src/bkauth/pkg/service/mock/app.go +++ b/src/bkauth/pkg/service/mock/app.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/service/types" - + types "bkauth/pkg/service/types" reflect "reflect" gomock "github.com/golang/mock/gomock" diff --git a/src/bkauth/pkg/service/mock/oauth_app.go b/src/bkauth/pkg/service/mock/oauth_app.go index ab5fa59..1e5dba4 100644 --- a/src/bkauth/pkg/service/mock/oauth_app.go +++ b/src/bkauth/pkg/service/mock/oauth_app.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/service/types" - + types "bkauth/pkg/service/types" reflect "reflect" gomock "github.com/golang/mock/gomock" diff --git a/src/bkauth/pkg/service/mock/scope.go b/src/bkauth/pkg/service/mock/scope.go index 0551aa0..496ffab 100644 --- a/src/bkauth/pkg/service/mock/scope.go +++ b/src/bkauth/pkg/service/mock/scope.go @@ -5,10 +5,9 @@ package mock import ( + types "bkauth/pkg/service/types" reflect "reflect" - "bkauth/pkg/service/types" - gomock "github.com/golang/mock/gomock" ) diff --git a/src/bkauth/pkg/service/mock/target.go b/src/bkauth/pkg/service/mock/target.go index d1c7b08..87b20c2 100644 --- a/src/bkauth/pkg/service/mock/target.go +++ b/src/bkauth/pkg/service/mock/target.go @@ -5,8 +5,7 @@ package mock import ( - "bkauth/pkg/service/types" - + types "bkauth/pkg/service/types" reflect "reflect" gomock "github.com/golang/mock/gomock" From 8f918bd16b9a56443209c2eae1e0c4a1bb12678b Mon Sep 17 00:00:00 2001 From: nannan00 <17491932+nannan00@users.noreply.github.com> Date: Thu, 6 Feb 2025 11:50:58 +0800 Subject: [PATCH 2/2] fix: lint --- src/bkauth/pkg/api/common/middleware.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bkauth/pkg/api/common/middleware.go b/src/bkauth/pkg/api/common/middleware.go index c3e2f40..12e1ab5 100644 --- a/src/bkauth/pkg/api/common/middleware.go +++ b/src/bkauth/pkg/api/common/middleware.go @@ -72,7 +72,10 @@ func AccessKeyExists() gin.HandlerFunc { // check access_key exists exists, err := service.NewAccessKeyService().ExistsByAppCodeAndID(appCode, accessKeyID) if err != nil { - util.SystemErrorJSONResponse(c, fmt.Errorf("query access_key_id(%d) of app(%s) fail, error: %w", accessKeyID, appCode, err)) + util.SystemErrorJSONResponse( + c, + fmt.Errorf("query access_key_id(%d) of app(%s) fail, error: %w", accessKeyID, appCode, err), + ) c.Abort() return }