github.com/polarismesh/polaris@v1.17.8/store/mysql/strategy.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package sqldb
    19  
    20  import (
    21  	"database/sql"
    22  	"fmt"
    23  	"strings"
    24  	"time"
    25  
    26  	"go.uber.org/zap"
    27  
    28  	"github.com/polarismesh/polaris/common/model"
    29  	"github.com/polarismesh/polaris/common/utils"
    30  	"github.com/polarismesh/polaris/store"
    31  )
    32  
    33  var (
    34  	RuleFilters map[string]string = map[string]string{
    35  		"res_id":         "ar.res_id",
    36  		"res_type":       "ar.res_type",
    37  		"default":        "ag.default",
    38  		"owner":          "ag.owner",
    39  		"name":           "ag.name",
    40  		"principal_id":   "ap.principal_id",
    41  		"principal_type": "ap.principal_role",
    42  	}
    43  
    44  	RuleNeedLikeFilters map[string]struct{} = map[string]struct{}{
    45  		"name": {},
    46  	}
    47  )
    48  
    49  type strategyStore struct {
    50  	master *BaseDB
    51  	slave  *BaseDB
    52  }
    53  
    54  func (s *strategyStore) AddStrategy(strategy *model.StrategyDetail) error {
    55  	if strategy.ID == "" || strategy.Name == "" || strategy.Owner == "" {
    56  		return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
    57  			"add auth_strategy missing some params, id is %s, name is %s, owner is %s",
    58  			strategy.ID, strategy.Name, strategy.Owner))
    59  	}
    60  
    61  	// 先清理无效数据
    62  	if err := s.cleanInvalidStrategy(strategy.Name, strategy.Owner); err != nil {
    63  		return store.Error(err)
    64  	}
    65  
    66  	err := RetryTransaction("addStrategy", func() error {
    67  		return s.addStrategy(strategy)
    68  	})
    69  	return store.Error(err)
    70  }
    71  
    72  func (s *strategyStore) addStrategy(strategy *model.StrategyDetail) error {
    73  	tx, err := s.master.Begin()
    74  	if err != nil {
    75  		return err
    76  	}
    77  	defer func() { _ = tx.Rollback() }()
    78  
    79  	isDefault := 0
    80  	if strategy.Default {
    81  		isDefault = 1
    82  	}
    83  
    84  	if err := s.addStrategyPrincipals(tx, strategy.ID, strategy.Principals); err != nil {
    85  		log.Error("[Store][Strategy] add auth_strategy principals", zap.Error(err))
    86  		return err
    87  	}
    88  
    89  	if err := s.addStrategyResources(tx, strategy.ID, strategy.Resources); err != nil {
    90  		log.Error("[Store][Strategy] add auth_strategy resources", zap.Error(err))
    91  		return err
    92  	}
    93  
    94  	// 保存策略主信息
    95  	saveMainSql := "INSERT INTO auth_strategy(`id`, `name`, `action`, `owner`, `comment`, `flag`, " +
    96  		" `default`, `revision`) VALUES (?,?,?,?,?,?,?,?)"
    97  	if _, err = tx.Exec(saveMainSql,
    98  		[]interface{}{
    99  			strategy.ID, strategy.Name, strategy.Action, strategy.Owner, strategy.Comment,
   100  			0, isDefault, strategy.Revision}...,
   101  	); err != nil {
   102  		log.Error("[Store][Strategy] add auth_strategy main info", zap.Error(err))
   103  		return err
   104  	}
   105  
   106  	if err := tx.Commit(); err != nil {
   107  		log.Errorf("[Store][Strategy] add auth_strategy tx commit err: %s", err.Error())
   108  		return err
   109  	}
   110  
   111  	return nil
   112  }
   113  
   114  // UpdateStrategy 更新鉴权规则
   115  func (s *strategyStore) UpdateStrategy(strategy *model.ModifyStrategyDetail) error {
   116  	if strategy.ID == "" {
   117  		return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
   118  			"update auth_strategy missing some params, id is %s", strategy.ID))
   119  	}
   120  
   121  	err := RetryTransaction("updateStrategy", func() error {
   122  		return s.updateStrategy(strategy)
   123  	})
   124  	return store.Error(err)
   125  }
   126  
   127  func (s *strategyStore) updateStrategy(strategy *model.ModifyStrategyDetail) error {
   128  	tx, err := s.master.Begin()
   129  	if err != nil {
   130  		return err
   131  	}
   132  	defer func() { _ = tx.Rollback() }()
   133  
   134  	// 调整 principal 信息
   135  	if err := s.addStrategyPrincipals(tx, strategy.ID, strategy.AddPrincipals); err != nil {
   136  		log.Errorf("[Store][Strategy] add strategy principal err: %s", err.Error())
   137  		return err
   138  	}
   139  	if err := s.deleteStrategyPrincipals(tx, strategy.ID, strategy.RemovePrincipals); err != nil {
   140  		log.Errorf("[Store][Strategy] remove strategy principal err: %s", err.Error())
   141  		return err
   142  	}
   143  
   144  	// 调整鉴权资源信息
   145  	if err := s.addStrategyResources(tx, strategy.ID, strategy.AddResources); err != nil {
   146  		log.Errorf("[Store][Strategy] add strategy resource err: %s", err.Error())
   147  		return err
   148  	}
   149  	if err := s.deleteStrategyResources(tx, strategy.ID, strategy.RemoveResources); err != nil {
   150  		log.Errorf("[Store][Strategy] remove strategy resource err: %s", err.Error())
   151  		return err
   152  	}
   153  
   154  	// 保存策略主信息
   155  	saveMainSql := "UPDATE auth_strategy SET action = ?, comment = ?, mtime = sysdate() WHERE id = ?"
   156  	if _, err = tx.Exec(saveMainSql, []interface{}{strategy.Action, strategy.Comment, strategy.ID}...); err != nil {
   157  		log.Error("[Store][Strategy] update strategy main info", zap.Error(err))
   158  		return err
   159  	}
   160  
   161  	if err := tx.Commit(); err != nil {
   162  		log.Errorf("[Store][Strategy] update auth_strategy tx commit err: %s", err.Error())
   163  		return err
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  func (s *strategyStore) DeleteStrategy(id string) error {
   170  	if id == "" {
   171  		return store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
   172  			"delete auth_strategy missing some params, id is %s", id))
   173  	}
   174  
   175  	err := RetryTransaction("deleteStrategy", func() error {
   176  		return s.deleteStrategy(id)
   177  	})
   178  	return store.Error(err)
   179  }
   180  
   181  func (s *strategyStore) deleteStrategy(id string) error {
   182  	tx, err := s.master.Begin()
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	defer func() { _ = tx.Rollback() }()
   188  
   189  	if _, err = tx.Exec("UPDATE auth_strategy SET flag = 1, mtime = sysdate() WHERE id = ?", []interface{}{
   190  		id,
   191  	}...); err != nil {
   192  		return err
   193  	}
   194  
   195  	if _, err = tx.Exec("DELETE FROM auth_strategy_resource WHERE strategy_id = ?", []interface{}{
   196  		id,
   197  	}...); err != nil {
   198  		return err
   199  	}
   200  
   201  	if _, err = tx.Exec("DELETE FROM auth_principal WHERE strategy_id = ?", []interface{}{
   202  		id,
   203  	}...); err != nil {
   204  		return err
   205  	}
   206  
   207  	if err := tx.Commit(); err != nil {
   208  		log.Errorf("[Store][Strategy] delete auth_strategy tx commit err: %s", err.Error())
   209  		return err
   210  	}
   211  	return nil
   212  }
   213  
   214  // addStrategyPrincipals
   215  func (s *strategyStore) addStrategyPrincipals(tx *BaseTx, id string, principals []model.Principal) error {
   216  	if len(principals) == 0 {
   217  		return nil
   218  	}
   219  
   220  	savePrincipalSql := "INSERT IGNORE INTO auth_principal(strategy_id, principal_id, principal_role) VALUES "
   221  	values := make([]string, 0)
   222  	args := make([]interface{}, 0)
   223  
   224  	for i := range principals {
   225  		principal := principals[i]
   226  		values = append(values, "(?,?,?)")
   227  		args = append(args, id, principal.PrincipalID, principal.PrincipalRole)
   228  	}
   229  
   230  	savePrincipalSql += strings.Join(values, ",")
   231  
   232  	log.Debug("[Store][Strategy] add strategy principal", zap.String("sql", savePrincipalSql),
   233  		zap.Any("args", args))
   234  
   235  	_, err := tx.Exec(savePrincipalSql, args...)
   236  	return err
   237  }
   238  
   239  // deleteStrategyPrincipals
   240  func (s *strategyStore) deleteStrategyPrincipals(tx *BaseTx, id string,
   241  	principals []model.Principal) error {
   242  	if len(principals) == 0 {
   243  		return nil
   244  	}
   245  
   246  	savePrincipalSql := "DELETE FROM auth_principal WHERE strategy_id = ? AND principal_id = ? " +
   247  		" AND principal_role = ?"
   248  	for i := range principals {
   249  		principal := principals[i]
   250  		if _, err := tx.Exec(savePrincipalSql, []interface{}{
   251  			id, principal.PrincipalID, principal.PrincipalRole,
   252  		}...); err != nil {
   253  			return err
   254  		}
   255  	}
   256  
   257  	return nil
   258  }
   259  
   260  func (s *strategyStore) addStrategyResources(tx *BaseTx, id string, resources []model.StrategyResource) error {
   261  	if len(resources) == 0 {
   262  		return nil
   263  	}
   264  
   265  	saveResSql := "REPLACE INTO auth_strategy_resource(strategy_id, res_type, res_id) VALUES "
   266  	values := make([]string, 0)
   267  	args := make([]interface{}, 0)
   268  
   269  	for i := range resources {
   270  		resource := resources[i]
   271  		values = append(values, "(?,?,?)")
   272  		args = append(args, resource.StrategyID, resource.ResType, resource.ResID)
   273  	}
   274  
   275  	if len(values) == 0 {
   276  		return nil
   277  	}
   278  
   279  	saveResSql += strings.Join(values, ",")
   280  	log.Debug("[Store][Strategy] add strategy resources", zap.String("sql", saveResSql),
   281  		zap.Any("args", args))
   282  	_, err := tx.Exec(saveResSql, args...)
   283  	return err
   284  }
   285  
   286  func (s *strategyStore) deleteStrategyResources(tx *BaseTx, id string,
   287  	resources []model.StrategyResource) error {
   288  
   289  	if len(resources) == 0 {
   290  		return nil
   291  	}
   292  
   293  	for i := range resources {
   294  		resource := resources[i]
   295  
   296  		saveResSql := "DELETE FROM auth_strategy_resource WHERE strategy_id = ? AND res_id = ? AND res_type = ?"
   297  		if _, err := tx.Exec(
   298  			saveResSql,
   299  			[]interface{}{resource.StrategyID, resource.ResID, resource.ResType}...,
   300  		); err != nil {
   301  			return err
   302  		}
   303  	}
   304  	return nil
   305  }
   306  
   307  // LooseAddStrategyResources loose add strategy resources
   308  func (s *strategyStore) LooseAddStrategyResources(resources []model.StrategyResource) error {
   309  	tx, err := s.master.Begin()
   310  	if err != nil {
   311  		return err
   312  	}
   313  	defer func() { _ = tx.Rollback() }()
   314  
   315  	// 保存策略的资源信息
   316  	for i := range resources {
   317  		resource := resources[i]
   318  
   319  		saveResSql := "REPLACE INTO auth_strategy_resource(strategy_id, res_type, res_id) VALUES (?,?,?)"
   320  		args := make([]interface{}, 0)
   321  		args = append(args, resource.StrategyID, resource.ResType, resource.ResID)
   322  
   323  		if _, err = tx.Exec(saveResSql, args...); err != nil {
   324  			err = store.Error(err)
   325  			if store.Code(err) == store.DuplicateEntryErr {
   326  				continue
   327  			}
   328  			return err
   329  		}
   330  
   331  		// 主要是为了能够触发 StrategyCache 的刷新逻辑
   332  		updateStrategySql := "UPDATE auth_strategy SET mtime = sysdate() WHERE id = ?"
   333  		if _, err = tx.Exec(updateStrategySql, resource.StrategyID); err != nil {
   334  			return err
   335  		}
   336  	}
   337  
   338  	if err := tx.Commit(); err != nil {
   339  		log.Errorf("[Store][Strategy] add auth_strategy tx commit err: %s", err.Error())
   340  		return err
   341  	}
   342  
   343  	return nil
   344  }
   345  
   346  // RemoveStrategyResources 删除策略的资源
   347  func (s *strategyStore) RemoveStrategyResources(resources []model.StrategyResource) error {
   348  	tx, err := s.master.Begin()
   349  	if err != nil {
   350  		return err
   351  	}
   352  	defer func() { _ = tx.Rollback() }()
   353  	for i := range resources {
   354  		resource := resources[i]
   355  
   356  		args := make([]interface{}, 0)
   357  		saveResSql := "DELETE FROM auth_strategy_resource WHERE strategy_id = ? AND res_id = ? AND res_type = ?"
   358  		args = append(args, resource.StrategyID, resource.ResID, resource.ResType)
   359  		if resource.StrategyID == "" {
   360  			saveResSql = "DELETE FROM auth_strategy_resource WHERE res_id = ? AND res_type = ?"
   361  			args = append(args, resource.ResID, resource.ResType)
   362  		}
   363  		if _, err := tx.Exec(saveResSql, args...); err != nil {
   364  			return err
   365  		}
   366  		// 主要是为了能够触发 StrategyCache 的刷新逻辑
   367  		updateStrategySql := "UPDATE auth_strategy SET mtime = sysdate() WHERE id = ?"
   368  		if _, err = tx.Exec(updateStrategySql, resource.StrategyID); err != nil {
   369  			return err
   370  		}
   371  	}
   372  
   373  	if err := tx.Commit(); err != nil {
   374  		log.Errorf("[Store][Strategy] add auth_strategy tx commit err: %s", err.Error())
   375  		return err
   376  	}
   377  
   378  	return nil
   379  }
   380  
   381  // GetStrategyDetail 获取策略详情
   382  func (s *strategyStore) GetStrategyDetail(id string) (*model.StrategyDetail, error) {
   383  	if id == "" {
   384  		return nil, store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
   385  			"get auth_strategy missing some params, id is %s", id))
   386  	}
   387  
   388  	querySql := "SELECT ag.id, ag.name, ag.action, ag.owner, ag.default, ag.comment, ag.revision, ag.flag, " +
   389  		" UNIX_TIMESTAMP(ag.ctime), UNIX_TIMESTAMP(ag.mtime) FROM auth_strategy AS ag WHERE ag.flag = 0 AND ag.id = ?"
   390  
   391  	row := s.master.QueryRow(querySql, id)
   392  
   393  	return s.getStrategyDetail(row)
   394  }
   395  
   396  // GetDefaultStrategyDetailByPrincipal 获取默认策略
   397  func (s *strategyStore) GetDefaultStrategyDetailByPrincipal(principalId string,
   398  	principalType model.PrincipalType) (*model.StrategyDetail, error) {
   399  
   400  	if principalId == "" {
   401  		return nil, store.NewStatusError(store.EmptyParamsErr, fmt.Sprintf(
   402  			"get auth_strategy missing some params, principal_id is %s", principalId))
   403  	}
   404  
   405  	querySql := `
   406  	 SELECT ag.id, ag.name, ag.action, ag.owner, ag.default
   407  		 , ag.comment, ag.revision, ag.flag, UNIX_TIMESTAMP(ag.ctime)
   408  		 , UNIX_TIMESTAMP(ag.mtime)
   409  	 FROM auth_strategy ag
   410  	 WHERE ag.flag = 0
   411  		 AND ag.default = 1
   412  		 AND ag.id IN (
   413  			 SELECT DISTINCT strategy_id
   414  			 FROM auth_principal
   415  			 WHERE principal_id = ?
   416  				 AND principal_role = ?
   417  		 )
   418  	 `
   419  
   420  	row := s.master.QueryRow(querySql, principalId, int(principalType))
   421  	return s.getStrategyDetail(row)
   422  }
   423  
   424  // getStrategyDetail
   425  func (s *strategyStore) getStrategyDetail(row *sql.Row) (*model.StrategyDetail, error) {
   426  	var (
   427  		ctime, mtime    int64
   428  		isDefault, flag int16
   429  	)
   430  	ret := new(model.StrategyDetail)
   431  	if err := row.Scan(&ret.ID, &ret.Name, &ret.Action, &ret.Owner, &isDefault, &ret.Comment,
   432  		&ret.Revision, &flag, &ctime, &mtime); err != nil {
   433  		switch err {
   434  		case sql.ErrNoRows:
   435  			return nil, nil
   436  		default:
   437  			return nil, store.Error(err)
   438  		}
   439  	}
   440  
   441  	ret.CreateTime = time.Unix(ctime, 0)
   442  	ret.ModifyTime = time.Unix(mtime, 0)
   443  	ret.Valid = flag == 0
   444  	ret.Default = isDefault == 1
   445  
   446  	resArr, err := s.getStrategyResources(s.slave.Query, ret.ID)
   447  	if err != nil {
   448  		return nil, store.Error(err)
   449  	}
   450  	principals, err := s.getStrategyPrincipals(s.slave.Query, ret.ID)
   451  	if err != nil {
   452  		return nil, store.Error(err)
   453  	}
   454  
   455  	ret.Resources = resArr
   456  	ret.Principals = principals
   457  	return ret, nil
   458  }
   459  
   460  // GetStrategies 获取策略列表
   461  func (s *strategyStore) GetStrategies(filters map[string]string, offset uint32, limit uint32) (uint32,
   462  	[]*model.StrategyDetail, error) {
   463  	showDetail := filters["show_detail"]
   464  	delete(filters, "show_detail")
   465  
   466  	filters["ag.flag"] = "0"
   467  
   468  	return s.listStrategies(filters, offset, limit, showDetail == "true")
   469  }
   470  
   471  // listStrategies
   472  func (s *strategyStore) listStrategies(filters map[string]string, offset uint32, limit uint32,
   473  	showDetail bool) (uint32, []*model.StrategyDetail, error) {
   474  
   475  	querySql :=
   476  		`SELECT
   477  			 ag.id,
   478  			 ag.name,
   479  			 ag.action,
   480  			 ag.owner,
   481  			 ag.comment,
   482  			 ag.default,
   483  			 ag.revision,
   484  			 ag.flag,
   485  			 UNIX_TIMESTAMP(ag.ctime),
   486  			 UNIX_TIMESTAMP(ag.mtime)
   487  		   FROM
   488  			 (
   489  			   auth_strategy ag
   490  			   LEFT JOIN auth_strategy_resource ar ON ag.id = ar.strategy_id
   491  			 )
   492  			 LEFT JOIN auth_principal ap ON ag.id = ap.strategy_id `
   493  	countSql := `
   494  	 SELECT COUNT(DISTINCT ag.id)
   495  	 FROM
   496  	   (
   497  		 auth_strategy ag
   498  		 LEFT JOIN auth_strategy_resource ar ON ag.id = ar.strategy_id
   499  	   )
   500  	   LEFT JOIN auth_principal ap ON ag.id = ap.strategy_id
   501  	 `
   502  
   503  	return s.queryStrategies(s.master.Query, filters, RuleFilters, querySql, countSql,
   504  		offset, limit, showDetail)
   505  }
   506  
   507  // queryStrategies 通用的查询策略列表
   508  func (s *strategyStore) queryStrategies(
   509  	handler QueryHandler,
   510  	filters map[string]string, mapping map[string]string,
   511  	querySqlPrefix string, countSqlPrefix string,
   512  	offset uint32, limit uint32, showDetail bool) (uint32, []*model.StrategyDetail, error) {
   513  	querySql := querySqlPrefix
   514  	countSql := countSqlPrefix
   515  
   516  	args := make([]interface{}, 0)
   517  	if len(filters) != 0 {
   518  		querySql += " WHERE "
   519  		countSql += " WHERE "
   520  		firstIndex := true
   521  		for k, v := range filters {
   522  			needLike := false
   523  			if !firstIndex {
   524  				querySql += " AND "
   525  				countSql += " AND "
   526  			}
   527  			firstIndex = false
   528  
   529  			if val, ok := mapping[k]; ok {
   530  				if _, exist := RuleNeedLikeFilters[k]; exist {
   531  					needLike = true
   532  				}
   533  				k = val
   534  			}
   535  
   536  			if needLike {
   537  				if utils.IsPrefixWildName(v) {
   538  					v = v[:len(v)-1]
   539  				}
   540  				querySql += (" " + k + " like ? ")
   541  				countSql += (" " + k + " like ? ")
   542  				args = append(args, "%"+v+"%")
   543  			} else if k == "ag.owner" {
   544  				querySql += " (ag.owner = ? OR (ap.principal_id = ? AND ap.principal_role = 1 )) "
   545  				countSql += " (ag.owner = ? OR (ap.principal_id = ? AND ap.principal_role = 1 )) "
   546  				args = append(args, v, v)
   547  			} else {
   548  				querySql += (" " + k + " = ? ")
   549  				countSql += (" " + k + " = ? ")
   550  				args = append(args, v)
   551  			}
   552  		}
   553  	}
   554  
   555  	count, err := queryEntryCount(s.master, countSql, args)
   556  	if err != nil {
   557  		return 0, nil, store.Error(err)
   558  	}
   559  
   560  	querySql += " GROUP BY ag.id ORDER BY ag.mtime LIMIT ?, ? "
   561  	args = append(args, offset, limit)
   562  
   563  	ret, err := s.collectStrategies(s.master.Query, querySql, args, showDetail)
   564  	if err != nil {
   565  		return 0, nil, err
   566  	}
   567  
   568  	return count, ret, nil
   569  }
   570  
   571  // collectStrategies 执行真正的 sql 并从 rows 中获取策略列表
   572  func (s *strategyStore) collectStrategies(handler QueryHandler, querySql string,
   573  	args []interface{}, showDetail bool) ([]*model.StrategyDetail, error) {
   574  	log.Debug("[Store][Strategy] get simple strategies", zap.String("query sql", querySql),
   575  		zap.Any("args", args))
   576  
   577  	rows, err := handler(querySql, args...)
   578  	if err != nil {
   579  		log.Error("[Store][Strategy] get simple strategies", zap.String("query sql", querySql),
   580  			zap.Any("args", args))
   581  		return nil, store.Error(err)
   582  	}
   583  	defer func() {
   584  		_ = rows.Close()
   585  	}()
   586  
   587  	idMap := make(map[string]struct{})
   588  
   589  	ret := make([]*model.StrategyDetail, 0, 16)
   590  	for rows.Next() {
   591  		detail, err := fetchRown2StrategyDetail(rows)
   592  		if err != nil {
   593  			return nil, store.Error(err)
   594  		}
   595  
   596  		// 为了避免数据重复被加入到 slice 中,做一个 map 去重
   597  		if _, ok := idMap[detail.ID]; ok {
   598  			continue
   599  		}
   600  		idMap[detail.ID] = struct{}{}
   601  
   602  		if showDetail {
   603  			resArr, err := s.getStrategyResources(s.slave.Query, detail.ID)
   604  			if err != nil {
   605  				return nil, store.Error(err)
   606  			}
   607  			principals, err := s.getStrategyPrincipals(s.slave.Query, detail.ID)
   608  			if err != nil {
   609  				return nil, store.Error(err)
   610  			}
   611  
   612  			detail.Resources = resArr
   613  			detail.Principals = principals
   614  		}
   615  
   616  		ret = append(ret, detail)
   617  	}
   618  
   619  	return ret, nil
   620  }
   621  
   622  func (s *strategyStore) GetStrategyDetailsForCache(mtime time.Time,
   623  	firstUpdate bool) ([]*model.StrategyDetail, error) {
   624  	tx, err := s.slave.Begin()
   625  	if err != nil {
   626  		return nil, store.Error(err)
   627  	}
   628  	defer func() { _ = tx.Commit() }()
   629  
   630  	args := make([]interface{}, 0)
   631  	querySql := "SELECT ag.id, ag.name, ag.action, ag.owner, ag.comment, ag.default, ag.revision, ag.flag, " +
   632  		" UNIX_TIMESTAMP(ag.ctime), UNIX_TIMESTAMP(ag.mtime) FROM auth_strategy ag "
   633  
   634  	if !firstUpdate {
   635  		querySql += " WHERE ag.mtime >= FROM_UNIXTIME(?)"
   636  		args = append(args, timeToTimestamp(mtime))
   637  	}
   638  
   639  	rows, err := tx.Query(querySql, args...)
   640  	if err != nil {
   641  		return nil, store.Error(err)
   642  	}
   643  	defer func() {
   644  		_ = rows.Close()
   645  	}()
   646  
   647  	ret := make([]*model.StrategyDetail, 0)
   648  	for rows.Next() {
   649  		detail, err := fetchRown2StrategyDetail(rows)
   650  		if err != nil {
   651  			return nil, store.Error(err)
   652  		}
   653  
   654  		resArr, err := s.getStrategyResources(s.slave.Query, detail.ID)
   655  		if err != nil {
   656  			return nil, store.Error(err)
   657  		}
   658  		principals, err := s.getStrategyPrincipals(s.slave.Query, detail.ID)
   659  		if err != nil {
   660  			return nil, store.Error(err)
   661  		}
   662  
   663  		detail.Resources = resArr
   664  		detail.Principals = principals
   665  
   666  		ret = append(ret, detail)
   667  	}
   668  
   669  	return ret, nil
   670  }
   671  
   672  // GetStrategyResources 获取对应 principal 能操作的所有资源
   673  func (s *strategyStore) GetStrategyResources(principalId string,
   674  	principalRole model.PrincipalType) ([]model.StrategyResource, error) {
   675  
   676  	querySql := "SELECT res_id, res_type FROM auth_strategy_resource WHERE strategy_id IN (SELECT DISTINCT " +
   677  		" ap.strategy_id FROM auth_principal ap join auth_strategy ar ON ap.strategy_id = ar.id WHERE ar.flag = 0 " +
   678  		" AND ap.principal_id = ? AND ap.principal_role = ? )"
   679  
   680  	rows, err := s.master.Query(querySql, principalId, principalRole)
   681  	if err != nil {
   682  		switch err {
   683  		case sql.ErrNoRows:
   684  			return nil, nil
   685  		default:
   686  			log.Error("[Store][Strategy] get principal link resource", zap.String("sql", querySql),
   687  				zap.String("principal-id", principalId), zap.Any("principal-type", principalRole))
   688  			return nil, store.Error(err)
   689  		}
   690  	}
   691  
   692  	defer rows.Close()
   693  
   694  	resArr := make([]model.StrategyResource, 0)
   695  
   696  	for rows.Next() {
   697  		res := new(model.StrategyResource)
   698  		if err := rows.Scan(&res.ResID, &res.ResType); err != nil {
   699  			return nil, store.Error(err)
   700  		}
   701  		resArr = append(resArr, *res)
   702  	}
   703  
   704  	return resArr, nil
   705  }
   706  
   707  func (s *strategyStore) getStrategyPrincipals(queryHander QueryHandler, id string) ([]model.Principal, error) {
   708  
   709  	rows, err := queryHander("SELECT principal_id, principal_role FROM auth_principal WHERE strategy_id = ?", id)
   710  	if err != nil {
   711  		switch err {
   712  		case sql.ErrNoRows:
   713  			log.Info("[Store][Strategy] not found link principals", zap.String("strategy-id", id))
   714  			return nil, nil
   715  		default:
   716  			return nil, store.Error(err)
   717  		}
   718  	}
   719  	defer rows.Close()
   720  
   721  	principals := make([]model.Principal, 0)
   722  
   723  	for rows.Next() {
   724  		res := new(model.Principal)
   725  		if err := rows.Scan(&res.PrincipalID, &res.PrincipalRole); err != nil {
   726  			return nil, store.Error(err)
   727  		}
   728  		principals = append(principals, *res)
   729  	}
   730  
   731  	return principals, nil
   732  }
   733  
   734  func (s *strategyStore) getStrategyResources(queryHander QueryHandler, id string) ([]model.StrategyResource, error) {
   735  	querySql := "SELECT res_id, res_type FROM auth_strategy_resource WHERE strategy_id = ?"
   736  	rows, err := queryHander(querySql, id)
   737  	if err != nil {
   738  		switch err {
   739  		case sql.ErrNoRows:
   740  			log.Info("[Store][Strategy] not found link resources", zap.String("strategy-id", id))
   741  			return nil, nil
   742  		default:
   743  			return nil, store.Error(err)
   744  		}
   745  	}
   746  	defer rows.Close()
   747  
   748  	resArr := make([]model.StrategyResource, 0)
   749  
   750  	for rows.Next() {
   751  		res := new(model.StrategyResource)
   752  		if err := rows.Scan(&res.ResID, &res.ResType); err != nil {
   753  			return nil, store.Error(err)
   754  		}
   755  		resArr = append(resArr, *res)
   756  	}
   757  
   758  	return resArr, nil
   759  }
   760  
   761  func fetchRown2StrategyDetail(rows *sql.Rows) (*model.StrategyDetail, error) {
   762  	var (
   763  		ctime, mtime    int64
   764  		isDefault, flag int16
   765  	)
   766  	ret := &model.StrategyDetail{
   767  		Resources: make([]model.StrategyResource, 0),
   768  	}
   769  
   770  	if err := rows.Scan(&ret.ID, &ret.Name, &ret.Action, &ret.Owner, &ret.Comment, &isDefault, &ret.Revision, &flag,
   771  		&ctime, &mtime); err != nil {
   772  		return nil, store.Error(err)
   773  	}
   774  
   775  	ret.CreateTime = time.Unix(ctime, 0)
   776  	ret.ModifyTime = time.Unix(mtime, 0)
   777  	ret.Valid = flag == 0
   778  
   779  	if isDefault == 1 {
   780  		ret.Default = true
   781  	}
   782  
   783  	return ret, nil
   784  }
   785  
   786  // cleanInvalidStrategy 按名称清理鉴权策略
   787  func (s *strategyStore) cleanInvalidStrategy(name, owner string) error {
   788  	log.Info("[Store][Strategy] clean invalid auth_strategy",
   789  		zap.String("name", name), zap.String("owner", owner))
   790  
   791  	tx, err := s.master.Begin()
   792  	if err != nil {
   793  		return err
   794  	}
   795  	defer func() { _ = tx.Rollback() }()
   796  
   797  	str := "delete from auth_strategy where name = ? and owner = ? and flag = 1"
   798  	if _, err = tx.Exec(str, name, owner); err != nil {
   799  		log.Errorf("[Store][Strategy] clean invalid auth_strategy(%s) err: %s", name, err.Error())
   800  		return err
   801  	}
   802  	if err := tx.Commit(); err != nil {
   803  		log.Errorf("[Store][Strategy] clean invalid auth_strategy tx commit err: %s", err.Error())
   804  		return err
   805  	}
   806  	return nil
   807  }
   808  
   809  // cleanLinkStrategy 清理与自己相关联的鉴权信息
   810  // step 1. 清理用户/用户组默认策略所关联的所有资源信息(直接走delete删除)
   811  // step 2. 清理用户/用户组默认策略
   812  // step 3. 清理用户/用户组所关联的其他鉴权策略的关联关系(直接走delete删除)
   813  func cleanLinkStrategy(tx *BaseTx, role model.PrincipalType, principalId, owner string) error {
   814  
   815  	// 清理默认策略对应的所有鉴权关联资源
   816  	removeResSql := `
   817  		 DELETE FROM auth_strategy_resource
   818  		 WHERE strategy_id IN (
   819  				 SELECT DISTINCT ag.id
   820  				 FROM auth_strategy ag
   821  				 WHERE ag.default = 1
   822  					 AND ag.owner = ?
   823  					 AND ag.id IN (
   824  						 SELECT DISTINCT strategy_id
   825  						 FROM auth_principal
   826  						 WHERE principal_id = ?
   827  							 AND principal_role = ?
   828  					 )
   829  			 )
   830  		 `
   831  
   832  	if _, err := tx.Exec(removeResSql, []interface{}{owner, principalId, role}...); err != nil {
   833  		return err
   834  	}
   835  
   836  	// 清理默认策略
   837  	cleanaRuleSql := `
   838  		 UPDATE auth_strategy AS ag
   839  		 SET ag.flag = 1
   840  		 WHERE ag.id IN (
   841  				 SELECT DISTINCT strategy_id
   842  				 FROM auth_principal
   843  				 WHERE principal_id = ?
   844  					 AND principal_role = ?
   845  			 )
   846  			 AND ag.default = 1
   847  			 AND ag.owner = ?
   848  	 `
   849  
   850  	if _, err := tx.Exec(cleanaRuleSql, []interface{}{principalId, role, owner}...); err != nil {
   851  		return err
   852  	}
   853  
   854  	// 调整所关联的鉴权策略的 mtime 数据,保证cache刷新可以获取到变更的数据信息
   855  	updateStrategySql := "UPDATE auth_strategy SET mtime = sysdate()  WHERE id IN (SELECT DISTINCT " +
   856  		" strategy_id FROM auth_principal WHERE principal_id = ? AND principal_role = ?)"
   857  	if _, err := tx.Exec(updateStrategySql, []interface{}{principalId, role}...); err != nil {
   858  		return err
   859  	}
   860  
   861  	// 清理所在的所有鉴权principal
   862  	cleanPrincipalSql := "DELETE FROM auth_principal WHERE principal_id = ? AND principal_role = ?"
   863  	if _, err := tx.Exec(cleanPrincipalSql, []interface{}{principalId, role}...); err != nil {
   864  		return err
   865  	}
   866  
   867  	return nil
   868  }