Sentinel 授权规则规则持久化( push模式 Nacos)

该博客介绍了如何将Sentinel的流控规则持久化到Nacos配置中心,包括修改YAML配置文件、创建Nacos转换器、提供者和发布者,以及更新Sentinel Dashboard的控制器和视图,实现规则的增删改查操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇Sentinel 流控规则规则

Sentinel下载地址(已修改)

  1. 修改应用服务的application.yml
    在这里插入图片描述

        authority:
          nacos:
            server-addr: localhost:8848 # nacos地址
            dataId: orderservice-authority-rules
            groupId: SENTINEL_GROUP
            rule-type: authority # 还可以是:degrade、authority、param-flow
  • 修改com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfig.java
    在这里插入图片描述
    @Bean
    public Converter<List<AuthorityRuleEntity>, String> authorityRuleEntityEncoder() {
        return JSON::toJSONString;
    }

    @Bean
    public Converter<String, List<AuthorityRuleEntity>> authorityRuleEntityDecoder() {
        return s -> JSON.parseArray(s, AuthorityRuleEntity.class);
    }

  • 修改com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil
    添加代码
  /**
     * 授权
     */
    public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
  • 新增com.alibaba.csp.sentinel.dashboard.rule.nacos.AuthorityRuleNacosProvider.java
    在这里插入图片描述
package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * Sentinel 授权规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/27 16:14
 * @Version 1.0
 **/
@Component("authorityRuleNacosProvider")
public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>>
{
    @Autowired
    private ConfigService configService;

    @Autowired
    private Converter<String, List<AuthorityRuleEntity>> converter;

    @Override
    public List<AuthorityRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

  • 新增com.alibaba.csp.sentinel.dashboard.rule.nacos.AuthorityRuleNacosPublisher.java
    在这里插入图片描述
package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Sentinel 授权规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/27 16:14
 * @Version 1.0
 **/
 @Component("authorityRuleNacosPublisher")
public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>>
{

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<AuthorityRuleEntity>, String> converter;

    @Override
    public CompletableFuture<Void> publish(String app, List<AuthorityRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return null;
        }
        configService.publishConfig(app + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, converter.convert(rules));
        return null;
    }
}

  • 新增com.alibaba.csp.sentinel.dashboard.controller.v2.AuthorityRuleControllerV2.java
    在这里插入图片描述
/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.dashboard.controller.v2;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;


/**
 * Sentinel 授权规则 持久化  Push 模式 Nacos
 * @Author jianghx
 * @Date 2021/12/24 11:47
 * @Version 1.0
 **/
@RestController
@RequestMapping(value = "/v2/authority")
public class AuthorityRuleControllerV2 {

    private final Logger logger = LoggerFactory.getLogger(AuthorityRuleControllerV2.class);

    @Autowired
    private RuleRepository<AuthorityRuleEntity, Long> repository;

    @Autowired
    @Qualifier("authorityRuleNacosProvider")
    private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;

    @Autowired
    @Qualifier("authorityRuleNacosPublisher")
    private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;

    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
                                                                        @RequestParam String ip,
                                                                        @RequestParam Integer port) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app cannot be null or empty");
        }
        if (StringUtil.isEmpty(ip)) {
            return Result.ofFail(-1, "ip cannot be null or empty");
        }
        if (port == null || port <= 0) {
            return Result.ofFail(-1, "Invalid parameter: port");
        }
        try {
            List<AuthorityRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (AuthorityRuleEntity entity : rules) {
                    entity.setApp(app);
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("Error when querying authority rules", throwable);
            return Result.ofFail(-1, throwable.getMessage());
        }
    }

    private <R> Result<R> checkEntityInternal(AuthorityRuleEntity entity) {
        if (entity == null) {
            return Result.ofFail(-1, "bad rule body");
        }
        if (StringUtil.isBlank(entity.getApp())) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isBlank(entity.getIp())) {
            return Result.ofFail(-1, "ip can't be null or empty");
        }
        if (entity.getPort() == null || entity.getPort() <= 0) {
            return Result.ofFail(-1, "port can't be null");
        }
        if (entity.getRule() == null) {
            return Result.ofFail(-1, "rule can't be null");
        }
        if (StringUtil.isBlank(entity.getResource())) {
            return Result.ofFail(-1, "resource name cannot be null or empty");
        }
        if (StringUtil.isBlank(entity.getLimitApp())) {
            return Result.ofFail(-1, "limitApp should be valid");
        }
        if (entity.getStrategy() != RuleConstant.AUTHORITY_WHITE
            && entity.getStrategy() != RuleConstant.AUTHORITY_BLACK) {
            return Result.ofFail(-1, "Unknown strategy (must be blacklist or whitelist)");
        }
        return null;
    }

    @PostMapping("/rule")
    @AuthAction(PrivilegeType.WRITE_RULE)
    public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) {
        Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        entity.setId(null);
        Date date = new Date();
        entity.setGmtCreate(date);
        entity.setGmtModified(date);
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
        } catch (Throwable throwable) {
            logger.error("Failed to add authority rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
//        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
//            logger.info("Publish authority rules failed after rule add");
//        }
        return Result.ofSuccess(entity);
    }

    @PutMapping("/rule/{id}")
    @AuthAction(PrivilegeType.WRITE_RULE)
    public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
                                                              @RequestBody AuthorityRuleEntity entity) {
        if (id == null || id <= 0) {
            return Result.ofFail(-1, "Invalid id");
        }
        Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
        if (checkResult != null) {
            return checkResult;
        }
        entity.setId(id);
        Date date = new Date();
        entity.setGmtCreate(null);
        entity.setGmtModified(date);
        try {
            entity = repository.save(entity);
            publishRules(entity.getApp());
            if (entity == null) {
                return Result.ofFail(-1, "Failed to save authority rule");
            }
        } catch (Throwable throwable) {
            logger.error("Failed to save authority rule", throwable);
            return Result.ofThrowable(-1, throwable);
        }
//        if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
//            logger.info("Publish authority rules failed after rule update");
//        }
        return Result.ofSuccess(entity);
    }

    @DeleteMapping("/rule/{id}")
    @AuthAction(PrivilegeType.DELETE_RULE)
    public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
        if (id == null) {
            return Result.ofFail(-1, "id cannot be null");
        }
        AuthorityRuleEntity oldEntity = repository.findById(id);
        if (oldEntity == null) {
            return Result.ofSuccess(null);
        }
        try {
            repository.delete(id);
            publishRules(oldEntity.getApp());
        } catch (Exception e) {
            return Result.ofFail(-1, e.getMessage());
        }
//        if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
//            logger.error("Publish authority rules failed after rule delete");
//        }
        return Result.ofSuccess(id);
    }

    private CompletableFuture<Void> publishRules(String app) throws Exception {
        List<AuthorityRuleEntity> rules = repository.findAllByApp(app);
        return rulePublisher.publish(app,  rules);
    }
}

  • 修改resources\app\scripts\directives\sidebar\sidebar.html
    在这里插入图片描述
    <li ui-sref-active="active" ng-if="entry.appType==0">
            <a ui-sref="dashboard.authority2({app: entry.app})">
              <i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;授权规则-Nacos</a>
          </li>

  • 修改resources\app\scripts\app.js
    在这里插入图片描述
    .state('dashboard.authority2', {
            templateUrl: 'app/views/authority_v2.html',
            url: '/v2/authority/:app',
            controller: 'AuthorityRuleController2',
            resolve: {
                loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
                    return $ocLazyLoad.load({
                        name: 'sentinelDashboardApp',
                        files: [
                            'app/scripts/controllers/authority_v2.js',
                        ]
                    });
                }]
            }
       })

  • 修改resources\dist\js\app.js
    在这里插入图片描述
   .state("dashboard.authority2", {
        templateUrl: "app/views/authority_v2.html",
        url: "/v2/authority/:app",
        controller: "AuthorityRuleController2",
        resolve: {
            loadMyFiles: ["$ocLazyLoad", function (e) {
                return e.load({name: "sentinelDashboardApp", files: ["app/scripts/controllers/authority_v2.js"]})
            }]
        }
    })
  • 新增resources\app\views\authority_v2.html
    在这里插入图片描述

将authority.html赋值一个名字改为authority_v2.html

  • 新增resources\app\scripts\controllers\authority_v2.js
    复制resources\app\scripts\controllers\authority.js改名resources\app\scripts\controllers\authority_v2.js并修改相关内容
    在这里插入图片描述
  • 新增resources\app\scripts\services\authority_service_v2.js

复制一个resources\app\scripts\services\authority_service_v2.js 并改名resources\app\scripts\services\authority_service_v2.js修改相关内容:
在这里插入图片描述
AuthorityRuleService改为AuthorityRuleService2
并将url添加前缀

/v2/

/**
 * Authority rule service.
 */
angular.module('sentinelDashboardApp').service('AuthorityRuleService2', ['$http', function ($http) {
    this.queryMachineRules = function(app, ip, port) {
        var param = {
            app: app,
            ip: ip,
            port: port
        };
        return $http({
            url: '/v2/authority/rules',
            params: param,
            method: 'GET'
        });
    };

    this.addNewRule = function(rule) {
        return $http({
            url: '/v2/authority/rule',
            data: rule,
            method: 'POST'
        });
    };

    this.saveRule = function (entity) {
        return $http({
            url: '/v2/authority/rule/' + entity.id,
            data: entity,
            method: 'PUT'
        });
    };

    this.deleteRule = function (entity) {
        return $http({
            url: '/v2/authority/rule/' + entity.id,
            method: 'DELETE'
        });
    };

    this.checkRuleValid = function checkRuleValid(rule) {
        if (rule.resource === undefined || rule.resource === '') {
            alert('资源名称不能为空');
            return false;
        }
        if (rule.limitApp === undefined || rule.limitApp === '') {
            alert('流控针对应用不能为空');
            return false;
        }
        if (rule.strategy === undefined) {
            alert('必须选择黑白名单模式');
            return false;
        }
        return true;
    };
}]);

  • 修改resources\dist\js\app.js
    在这里插入图片描述
 angular.module("sentinelDashboardApp").service("AuthorityRuleService2", ["$http", function (a) {
    this.queryMachineRules = function (e, t, r) {
        return a({url: "/v2/authority/rules", params: {app: e, ip: t, port: r}, method: "GET"})
    }, this.addNewRule = function (e) {
        return a({url: "/v2/authority/rule", data: e, method: "POST"})
    }, this.saveRule = function (e) {
        return a({url: "/v2/authority/rule/" + e.id, data: e, method: "PUT"})
    }, this.deleteRule = function (e) {
        return a({url: "/v2/authority/rule/" + e.id, method: "DELETE"})
    }, this.checkRuleValid = function (e) {
        return void 0 === e.resource || "" === e.resource ? (alert("资源名称不能为空"), !1) : void 0 === e.limitApp || "" === e.limitApp ? (alert("流控针对应用不能为空"), !1) : void 0 !== e.strategy || (alert("必须选择黑白名单模式"), !1)
    }
}])
  • 修改resources\gulpfile.js
    在这里插入图片描述
 'app/scripts/services/authority_service_v2.js',
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值