Add support for authority rule configuration in Sentinel Dashboard (#189)
- Update dashboard API client to support authority rule commands - Add REST API and frontend page for authority rules Signed-off-by: Eric Zhao <sczyh16@gmail.com>
This commit is contained in:
parent
bbea62a5c7
commit
0855809149
|
|
@ -331,6 +331,27 @@ public class SentinelApiClient {
|
|||
return true;
|
||||
}
|
||||
|
||||
public boolean setAuthorityRuleOfMachine(String app, String ip, int port, List<AuthorityRuleEntity> rules) {
|
||||
if (rules == null) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtil.isBlank(ip) || port <= 0) {
|
||||
throw new IllegalArgumentException("Invalid IP or port");
|
||||
}
|
||||
String data = JSON.toJSONString(
|
||||
rules.stream().map(AuthorityRuleEntity::getRule).collect(Collectors.toList()));
|
||||
try {
|
||||
data = URLEncoder.encode(data, DEFAULT_CHARSET.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.info("Encode rule error", e);
|
||||
return false;
|
||||
}
|
||||
String url = "http://" + ip + ":" + port + "/" + SET_RULES_PATH + "?type=" + AUTHORITY_TYPE + "&data=" + data;
|
||||
String result = httpGetContent(url);
|
||||
logger.info("Push authority rules: " + result);
|
||||
return true;
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> setParamFlowRuleOfMachine(String app, String ip, int port, List<ParamFlowRuleEntity> rules) {
|
||||
if (rules == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
|
|
|||
|
|
@ -18,12 +18,16 @@ package com.taobao.csp.sentinel.dashboard.datasource.entity.rule;
|
|||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
|
||||
import com.alibaba.csp.sentinel.util.AssertUtil;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
public class AuthorityRuleEntity extends AbstractRuleEntity<AuthorityRule> {
|
||||
|
||||
public AuthorityRuleEntity() {}
|
||||
|
||||
public AuthorityRuleEntity(AuthorityRule authorityRule) {
|
||||
AssertUtil.notNull(authorityRule, "Authority rule should not be null");
|
||||
this.rule = authorityRule;
|
||||
|
|
@ -37,14 +41,17 @@ public class AuthorityRuleEntity extends AbstractRuleEntity<AuthorityRule> {
|
|||
return entity;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getLimitApp() {
|
||||
return rule.getLimitApp();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public String getResource() {
|
||||
return rule.getResource();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public int getStrategy() {
|
||||
return rule.getStrategy();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.taobao.csp.sentinel.dashboard.repository.rule;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* In-memory storage for authority rules.
|
||||
*
|
||||
* @author Eric Zhao
|
||||
* @since 0.2.1
|
||||
*/
|
||||
@Component
|
||||
public class InMemAuthorityRuleStore extends InMemoryRuleRepositoryAdapter<AuthorityRuleEntity> {
|
||||
|
||||
private static AtomicLong ids = new AtomicLong(0);
|
||||
|
||||
@Override
|
||||
protected long nextId() {
|
||||
return ids.incrementAndGet();
|
||||
}
|
||||
}
|
||||
|
|
@ -15,11 +15,27 @@
|
|||
*/
|
||||
package com.taobao.csp.sentinel.dashboard.view;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
import com.taobao.csp.sentinel.dashboard.client.SentinelApiClient;
|
||||
import com.taobao.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
|
||||
import com.taobao.csp.sentinel.dashboard.discovery.MachineInfo;
|
||||
import com.taobao.csp.sentinel.dashboard.repository.rule.RuleRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
|
|
@ -34,4 +50,134 @@ public class AuthorityRuleController {
|
|||
|
||||
@Autowired
|
||||
private SentinelApiClient sentinelApiClient;
|
||||
@Autowired
|
||||
private RuleRepository<AuthorityRuleEntity, Long> repository;
|
||||
|
||||
@GetMapping("/rules")
|
||||
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 = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
|
||||
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")
|
||||
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);
|
||||
} 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}")
|
||||
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);
|
||||
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}")
|
||||
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);
|
||||
} 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 boolean publishRules(String app, String ip, Integer port) {
|
||||
List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
|
||||
return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,22 @@ angular
|
|||
}
|
||||
})
|
||||
|
||||
.state('dashboard.authority', {
|
||||
templateUrl: 'app/views/authority.html',
|
||||
url: '/authority/:app',
|
||||
controller: 'AuthorityRuleController',
|
||||
resolve: {
|
||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
|
||||
return $ocLazyLoad.load({
|
||||
name: 'sentinelDashboardApp',
|
||||
files: [
|
||||
'app/scripts/controllers/authority.js',
|
||||
]
|
||||
});
|
||||
}]
|
||||
}
|
||||
})
|
||||
|
||||
.state('dashboard.degrade', {
|
||||
templateUrl: 'app/views/degrade.html',
|
||||
url: '/degrade/:app',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,243 @@
|
|||
/**
|
||||
* Authority rule controller.
|
||||
*/
|
||||
angular.module('sentinelDashboardApp').controller('AuthorityRuleController', ['$scope', '$stateParams', 'AuthorityRuleService', 'ngDialog',
|
||||
'MachineService',
|
||||
function ($scope, $stateParams, AuthorityRuleService, ngDialog,
|
||||
MachineService) {
|
||||
$scope.app = $stateParams.app;
|
||||
|
||||
$scope.rulesPageConfig = {
|
||||
pageSize: 10,
|
||||
currentPageIndex: 1,
|
||||
totalPage: 1,
|
||||
totalCount: 0,
|
||||
};
|
||||
$scope.macsInputConfig = {
|
||||
searchField: ['text', 'value'],
|
||||
persist: true,
|
||||
create: false,
|
||||
maxItems: 1,
|
||||
render: {
|
||||
item: function (data, escape) {
|
||||
return '<div>' + escape(data.text) + '</div>';
|
||||
}
|
||||
},
|
||||
onChange: function (value, oldValue) {
|
||||
$scope.macInputModel = value;
|
||||
}
|
||||
};
|
||||
|
||||
function getMachineRules() {
|
||||
if (!$scope.macInputModel) {
|
||||
return;
|
||||
}
|
||||
let mac = $scope.macInputModel.split(':');
|
||||
AuthorityRuleService.queryMachineRules($scope.app, mac[0], mac[1])
|
||||
.success(function (data) {
|
||||
if (data.code === 0 && data.data) {
|
||||
$scope.loadError = undefined;
|
||||
$scope.rules = data.data;
|
||||
$scope.rulesPageConfig.totalCount = $scope.rules.length;
|
||||
} else {
|
||||
$scope.rules = [];
|
||||
$scope.rulesPageConfig.totalCount = 0;
|
||||
$scope.loadError = {message: data.msg};
|
||||
}
|
||||
})
|
||||
.error((data, header, config, status) => {
|
||||
$scope.loadError = {message: "未知错误"};
|
||||
});
|
||||
};
|
||||
$scope.getMachineRules = getMachineRules;
|
||||
getMachineRules();
|
||||
|
||||
var authorityRuleDialog;
|
||||
|
||||
$scope.editRule = function (rule) {
|
||||
$scope.currentRule = rule;
|
||||
$scope.authorityRuleDialog = {
|
||||
title: '编辑授权规则',
|
||||
type: 'edit',
|
||||
confirmBtnText: '保存',
|
||||
};
|
||||
authorityRuleDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/authority-rule-dialog.html',
|
||||
width: 680,
|
||||
overlay: true,
|
||||
scope: $scope
|
||||
});
|
||||
};
|
||||
|
||||
$scope.addNewRule = function () {
|
||||
var mac = $scope.macInputModel.split(':');
|
||||
$scope.currentRule = {
|
||||
app: $scope.app,
|
||||
ip: mac[0],
|
||||
port: mac[1],
|
||||
rule: {
|
||||
strategy: 0,
|
||||
limitApp: '',
|
||||
}
|
||||
};
|
||||
$scope.authorityRuleDialog = {
|
||||
title: '新增授权规则',
|
||||
type: 'add',
|
||||
confirmBtnText: '新增',
|
||||
showAdvanceButton: true,
|
||||
};
|
||||
authorityRuleDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/authority-rule-dialog.html',
|
||||
width: 680,
|
||||
overlay: true,
|
||||
scope: $scope
|
||||
});
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
$scope.saveRule = function () {
|
||||
if (!checkRuleValid($scope.currentRule.rule)) {
|
||||
return;
|
||||
}
|
||||
if ($scope.authorityRuleDialog.type === 'add') {
|
||||
addNewRuleAndPush($scope.currentRule);
|
||||
} else if ($scope.authorityRuleDialog.type === 'edit') {
|
||||
saveRuleAndPush($scope.currentRule, true);
|
||||
}
|
||||
};
|
||||
|
||||
function addNewRuleAndPush(rule) {
|
||||
AuthorityRuleService.addNewRule(rule).success((data) => {
|
||||
if (data.success) {
|
||||
getMachineRules();
|
||||
authorityRuleDialog.close();
|
||||
} else {
|
||||
alert('添加规则失败:' + data.msg);
|
||||
}
|
||||
}).error((data) => {
|
||||
if (data) {
|
||||
alert('添加规则失败:' + data.msg);
|
||||
} else {
|
||||
alert("添加规则失败:未知错误");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function saveRuleAndPush(rule, edit) {
|
||||
AuthorityRuleService.saveRule(rule).success(function (data) {
|
||||
if (data.success) {
|
||||
alert("修改规则成功");
|
||||
getMachineRules();
|
||||
if (edit) {
|
||||
authorityRuleDialog.close();
|
||||
} else {
|
||||
confirmDialog.close();
|
||||
}
|
||||
} else {
|
||||
alert('修改规则失败:' + data.msg);
|
||||
}
|
||||
}).error((data) => {
|
||||
if (data) {
|
||||
alert('修改规则失败:' + data.msg);
|
||||
} else {
|
||||
alert("修改规则失败:未知错误");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteRuleAndPush(entity) {
|
||||
if (entity.id === undefined || isNaN(entity.id)) {
|
||||
alert('规则 ID 不合法!');
|
||||
return;
|
||||
}
|
||||
AuthorityRuleService.deleteRule(entity).success((data) => {
|
||||
if (data.code == 0) {
|
||||
getMachineRules();
|
||||
confirmDialog.close();
|
||||
} else {
|
||||
alert('删除规则失败:' + data.msg);
|
||||
}
|
||||
}).error((data) => {
|
||||
if (data) {
|
||||
alert('删除规则失败:' + data.msg);
|
||||
} else {
|
||||
alert("删除规则失败:未知错误");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var confirmDialog;
|
||||
$scope.deleteRule = function (ruleEntity) {
|
||||
$scope.currentRule = ruleEntity;
|
||||
$scope.confirmDialog = {
|
||||
title: '删除授权规则',
|
||||
type: 'delete_rule',
|
||||
attentionTitle: '请确认是否删除如下授权限流规则',
|
||||
attention: '资源名: ' + ruleEntity.rule.resource + ', 流控应用: ' + ruleEntity.rule.limitApp +
|
||||
', 类型: ' + (ruleEntity.rule.strategy === 0 ? '白名单' : '黑名单'),
|
||||
confirmBtnText: '删除',
|
||||
};
|
||||
confirmDialog = ngDialog.open({
|
||||
template: '/app/views/dialog/confirm-dialog.html',
|
||||
scope: $scope,
|
||||
overlay: true
|
||||
});
|
||||
};
|
||||
|
||||
$scope.confirm = function () {
|
||||
if ($scope.confirmDialog.type === 'delete_rule') {
|
||||
deleteRuleAndPush($scope.currentRule);
|
||||
} else {
|
||||
console.error('error');
|
||||
}
|
||||
};
|
||||
|
||||
queryAppMachines();
|
||||
|
||||
function queryAppMachines() {
|
||||
MachineService.getAppMachines($scope.app).success(
|
||||
function (data) {
|
||||
if (data.code == 0) {
|
||||
// $scope.machines = data.data;
|
||||
if (data.data) {
|
||||
$scope.machines = [];
|
||||
$scope.macsInputOptions = [];
|
||||
data.data.forEach(function (item) {
|
||||
if (item.health) {
|
||||
$scope.macsInputOptions.push({
|
||||
text: item.ip + ':' + item.port,
|
||||
value: item.ip + ':' + item.port
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if ($scope.macsInputOptions.length > 0) {
|
||||
$scope.macInputModel = $scope.macsInputOptions[0].value;
|
||||
}
|
||||
} else {
|
||||
$scope.macsInputOptions = [];
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
$scope.$watch('macInputModel', function () {
|
||||
if ($scope.macInputModel) {
|
||||
getMachineRules();
|
||||
}
|
||||
});
|
||||
}]);
|
||||
|
|
@ -48,6 +48,10 @@
|
|||
<a ui-sref="dashboard.system({app: entry.app})">
|
||||
<i class="glyphicon glyphicon-lock"></i> 系统规则</a>
|
||||
</li>
|
||||
<li ui-sref-active="active">
|
||||
<a ui-sref="dashboard.authority({app: entry.app})">
|
||||
<i class="glyphicon glyphicon-check"></i> 授权规则</a>
|
||||
</li>
|
||||
<li ui-sref-active="active">
|
||||
<a ui-sref="dashboard.machine({app: entry.app})">
|
||||
<i class="glyphicon glyphicon-th-list"></i> 机器列表</a>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Authority rule service.
|
||||
*/
|
||||
angular.module('sentinelDashboardApp').service('AuthorityRuleService', ['$http', function ($http) {
|
||||
this.queryMachineRules = function(app, ip, port) {
|
||||
var param = {
|
||||
app: app,
|
||||
ip: ip,
|
||||
port: port
|
||||
};
|
||||
return $http({
|
||||
url: '/authority/rules',
|
||||
params: param,
|
||||
method: 'GET'
|
||||
});
|
||||
};
|
||||
|
||||
this.addNewRule = function(rule) {
|
||||
return $http({
|
||||
url: '/authority/rule',
|
||||
data: rule,
|
||||
method: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
this.saveRule = function (entity) {
|
||||
return $http({
|
||||
url: '/authority/rule/' + entity.id,
|
||||
data: entity,
|
||||
method: 'PUT'
|
||||
});
|
||||
};
|
||||
|
||||
this.deleteRule = function (entity) {
|
||||
return $http({
|
||||
url: '/authority/rule/' + entity.id,
|
||||
method: 'DELETE'
|
||||
});
|
||||
};
|
||||
}]);
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;">
|
||||
<div class="col-md-6" style="margin-bottom: 10px;">
|
||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()">
|
||||
<i class="fa fa-plus"></i> 新增授权规则</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="inputs-header">
|
||||
<span class="brand" style="font-size: 13px;">授权规则</span>
|
||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button>
|
||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey">
|
||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;">
|
||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel"
|
||||
placeholder="机器"></selectize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--.tools-header -->
|
||||
<div class="card-body" style="padding: 0px 0px;">
|
||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;">
|
||||
<thead>
|
||||
<tr style="background: #F3F5F7;">
|
||||
<td style="width: 40%">
|
||||
资源名
|
||||
</td>
|
||||
<td style="width: 10%;">
|
||||
流控应用
|
||||
</td>
|
||||
<td style="width: 10%;">
|
||||
授权类型
|
||||
</td>
|
||||
<td style="width: 12%;">
|
||||
操作
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr dir-paginate="ruleEntity in rules | filter: searchKey | itemsPerPage: rulesPageConfig.pageSize " current-page="rulesPageConfig.currentPageIndex"
|
||||
pagination-id="entriesPagination">
|
||||
<td style="word-wrap:break-word;word-break:break-all;">{{ruleEntity.rule.resource}}</td>
|
||||
<td style="word-wrap:break-word;word-break:break-all;">{{ruleEntity.rule.limitApp }}</td>
|
||||
<td>
|
||||
<span ng-if="ruleEntity.rule.strategy == 0">白名单</span>
|
||||
<span ng-if="ruleEntity.rule.strategy == 1">黑名单</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(ruleEntity)" style="font-size: 12px; height:25px;">编辑</button>
|
||||
<button class="btn btn-xs btn-default" type="button" ng-click="deleteRule(ruleEntity)" style="font-size: 12px; height:25px;">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- .card-body -->
|
||||
<div class="pagination-footer">
|
||||
<dir-pagination-controls boundary-links="true" template-url="app/views/pagination.tpl.html" pagination-id="entriesPagination"
|
||||
on-page-change="">
|
||||
</dir-pagination-controls>
|
||||
<div class="tools" style="">
|
||||
<span>共 {{rulesPageConfig.totalCount}} 条记录, </span>
|
||||
<span>
|
||||
每页
|
||||
<input class="form-control" ng-model="rulesPageConfig.pageSize"> 条记录
|
||||
</span>
|
||||
</div>
|
||||
<!-- .tools -->
|
||||
</div>
|
||||
<!-- pagination-footer -->
|
||||
</div>
|
||||
<!-- .card -->
|
||||
</div>
|
||||
<!-- .col-md-12 -->
|
||||
</div>
|
||||
<!-- -->
|
||||
</div>
|
||||
<!-- .container-fluid -->
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<div>
|
||||
<span class="brand" style="font-weight:bold;">{{authorityRuleDialog.title}}</span>
|
||||
<div class="card" style="margin-top: 20px;margin-bottom: 10px;">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<form role="form" class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">资源名</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" ng-if="authorityRuleDialog.type == 'edit'" class="form-control" placeholder="资源名" ng-model='currentRule.rule.resource'
|
||||
disabled="" />
|
||||
<input type="text" ng-if="authorityRuleDialog.type == 'add'" class="form-control highlight-border" placeholder="资源名称" ng-model='currentRule.rule.resource'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">流控应用</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control highlight-border" ng-model='currentRule.rule.limitApp' placeholder='指调用方,多个调用方名称用半角英文逗号(,)分隔'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">授权类型</label>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-control highlight-border" align="center">
|
||||
<input type="radio" name="strategy" value="0" checked ng-model='currentRule.rule.strategy' /> 白名单
|
||||
<input type="radio" name="strategy" value="1" ng-model='currentRule.rule.strategy' /> 黑名单
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div clss="row" style="margin-top: 20px;">
|
||||
<button class="btn btn-default-inverse" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="closeThisDialog()">取消</button>
|
||||
<button class="btn btn-danger-inverse" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="saveRule()">{{authorityRuleDialog.confirmBtnText}}</button>
|
||||
<button ng-if="authorityRuleDialog.saveAndContinueBtnText" class="btn btn-default" style="float:right; height: 30px;font-size: 12px;"
|
||||
ng-click="saveRuleAndContinue()">{{authorityRuleDialog.saveAndContinueBtnText}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
2
sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
vendored
Normal file → Executable file
2
sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
vendored
Normal file → Executable file
File diff suppressed because one or more lines are too long
|
|
@ -51,6 +51,7 @@ const JS_APP = [
|
|||
'app/scripts/services/identityservice.js',
|
||||
'app/scripts/services/metricservice.js',
|
||||
'app/scripts/services/param_flow_service.js',
|
||||
'app/scripts/services/authority_service.js',
|
||||
];
|
||||
|
||||
gulp.task('lib', function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue