Browse Source

dashboard: Add a simple login page to support basic auth (#659)

- Add `AuthController` and `SimpleWebAuthServiceImpl`
- Update `AuthFilter`
- Add a simple login page and frontend interceptor to support auth check and session storage
master
cdfive Eric Zhao 5 years ago
parent
commit
4acb907050
18 changed files with 514 additions and 56 deletions
  1. +8
    -1
      sentinel-dashboard/README.md
  2. +2
    -0
      sentinel-dashboard/Sentinel_Dashboard_Feature.md
  3. +78
    -0
      sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/auth/SimpleWebAuthServiceImpl.java
  4. +35
    -2
      sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/DashboardConfig.java
  5. +5
    -38
      sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java
  6. +80
    -0
      sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthController.java
  7. +118
    -0
      sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/AuthFilter.java
  8. +6
    -0
      sentinel-dashboard/src/main/resources/application.properties
  9. +49
    -8
      sentinel-dashboard/src/main/webapp/resources/app/scripts/app.js
  10. +36
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/login.js
  11. +5
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/header/header.html
  12. +16
    -2
      sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/header/header.js
  13. +18
    -0
      sentinel-dashboard/src/main/webapp/resources/app/scripts/services/auth_service.js
  14. +29
    -0
      sentinel-dashboard/src/main/webapp/resources/app/views/login.html
  15. +1
    -1
      sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
  16. +1
    -1
      sentinel-dashboard/src/main/webapp/resources/dist/js/app.vendor.js
  17. +1
    -0
      sentinel-dashboard/src/main/webapp/resources/gulpfile.js
  18. +26
    -3
      sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/config/DashboardConfigTest.java

+ 8
- 1
sentinel-dashboard/README.md View File

@@ -20,12 +20,19 @@ mvn clean package

```bash
java -Dserver.port=8080 \
-Dserver.servlet.session.timeout=7200 \
-Dauth.username=sentinel \
-Dauth.password=123456 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar target/sentinel-dashboard.jar
```

上述命令中我们指定几个 JVM 参数,其中 `-Dserver.port=8080` 用于指定 Spring Boot 启动端口为 `8080`,其余几个是 Sentinel 客户端的参数。
上述命令中我们指定几个 JVM 参数,其中:
`-Dserver.port=8080` 用于指定 Spring Boot 启动端口为 `8080`;
`-Dserver.servlet.session.timeout=7200` 用于指定 Spring Boot 服务器端会话的过期时间,如不带后缀的7200表示7200秒,60m表示60分钟,默认为30分钟;
`-Dauth.username=sentinel`、 `-Dauth.password=123456` 用于指定控制台的登录用户和密码分别为sentinel和123456,如果省略这2个参数,默认用户和密码均为sentinel;
其余几个是 Sentinel 客户端的参数。
为便于演示,我们对控制台本身加入了流量控制功能,具体做法是引入 `CommonFilter` 这个 Sentinel 拦截器。上述 JVM 参数的含义是:

| 参数 | 作用 |


+ 2
- 0
sentinel-dashboard/Sentinel_Dashboard_Feature.md View File

@@ -55,6 +55,8 @@ Sentinel 提供了多种规则来保护系统的不同部分。流量控制规

项 | 类型 | 默认值 | 最小值 | 描述
--- | --- | --- | --- | ---
sentinel.dashboard.auth.username | String | sentinel | 无 | 登录控制台的用户,默认sentinel
sentinel.dashboard.auth.password | String | sentinel | 无 | 登录控制台的密码,默认sentinel
sentinel.dashboard.app.hideAppNoMachineMillis | Integer | 0 | 60000 | 是否隐藏无健康节点的应用,距离最近一次主机心跳时间的毫秒数,默认关闭
sentinel.dashboard.removeAppNoMachineMillis | Integer | 0 | 120000 | 是否自动删除无健康节点的应用,距离最近一次其下节点的心跳时间毫秒数,默认关闭
sentinel.dashboard.unhealthyMachineMillis | Integer | 60000 | 30000 | 主机失联判定,不可关闭


+ 78
- 0
sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/auth/SimpleWebAuthServiceImpl.java View File

@@ -0,0 +1,78 @@
/*
* 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.auth;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
* @author cdfive
* @since 1.6.0
*/
@Primary
@Component
public class SimpleWebAuthServiceImpl implements AuthService<HttpServletRequest> {

public static final String WEB_SESSTION_KEY = "session_sentinel_admin";

@Override
public AuthUser getAuthUser(HttpServletRequest request) {
HttpSession session = request.getSession();
Object sentinelUserObj = session.getAttribute(SimpleWebAuthServiceImpl.WEB_SESSTION_KEY);
if (sentinelUserObj != null && sentinelUserObj instanceof AuthUser) {
return (AuthUser) sentinelUserObj;
}

return null;
}

public static final class SimpleWebAuthUserImpl implements AuthUser {

private String username;

public SimpleWebAuthUserImpl(String username) {
this.username = username;
}

@Override
public boolean authTarget(String target, PrivilegeType privilegeType) {
return true;
}

@Override
public boolean isSuperUser() {
return true;
}

@Override
public String getNickName() {
return username;
}

@Override
public String getLoginName() {
return username;
}

@Override
public String getId() {
return username;
}
}
}

+ 35
- 2
sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/DashboardConfig.java View File

@@ -37,6 +37,16 @@ public class DashboardConfig {

public static final int DEFAULT_MACHINE_HEALTHY_TIMEOUT_MS = 60_000;

/**
* Login username
*/
public static final String CONFIG_AUTH_USERNAME = "sentinel.dashboard.auth.username";

/**
* Login password
*/
public static final String CONFIG_AUTH_PASSWORD = "sentinel.dashboard.auth.password";

/**
* Hide application name in sidebar when it has no healthy machines after specific period in millisecond.
*/
@@ -70,7 +80,22 @@ public class DashboardConfig {
}
return "";
}

protected static String getConfigStr(String name) {
if (cacheMap.containsKey(name)) {
return (String) cacheMap.get(name);
}

String val = getConfig(name);

if (StringUtils.isBlank(val)) {
return null;
}

cacheMap.put(name, val);
return val;
}

protected static int getConfigInt(String name, int defaultVal, int minVal) {
if (cacheMap.containsKey(name)) {
return (int)cacheMap.get(name);
@@ -84,7 +109,15 @@ public class DashboardConfig {
cacheMap.put(name, val);
return val;
}

public static String getAuthUsername() {
return getConfigStr(CONFIG_AUTH_USERNAME);
}

public static String getAuthPassword() {
return getConfigStr(CONFIG_AUTH_PASSWORD);
}

public static int getHideAppNoMachineMillis() {
return getConfigInt(CONFIG_HIDE_APP_NO_MACHINE_MILLIS, 0, 60000);
}


+ 5
- 38
sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/config/WebConfig.java View File

@@ -15,21 +15,8 @@
*/
package com.alibaba.csp.sentinel.dashboard.config;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.AuthUser;

import com.alibaba.csp.sentinel.dashboard.filter.AuthFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -40,6 +27,8 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.Filter;

/**
* @author leyou
*/
@@ -49,7 +38,7 @@ public class WebConfig implements WebMvcConfigurer {
private final Logger logger = LoggerFactory.getLogger(WebConfig.class);

@Autowired
private AuthService<HttpServletRequest> authService;
private AuthFilter authFilter;

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
@@ -81,29 +70,7 @@ public class WebConfig implements WebMvcConfigurer {
@Bean
public FilterRegistrationBean authenticationFilterRegistration() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new Filter() {

@Override
public void init(FilterConfig filterConfig) throws ServletException { }

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
AuthUser authUser = authService.getAuthUser(request);
// authentication fail
if (authUser == null) {
PrintWriter writer = servletResponse.getWriter();
writer.append("login needed");
writer.flush();
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}

@Override
public void destroy() { }
});
registration.setFilter(authFilter);
registration.addUrlPatterns("/*");
registration.setName("authenticationFilter");
registration.setOrder(0);


+ 80
- 0
sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthController.java View File

@@ -0,0 +1,80 @@
/*
* 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;

import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import com.alibaba.csp.sentinel.dashboard.auth.SimpleWebAuthServiceImpl;
import com.alibaba.csp.sentinel.dashboard.config.DashboardConfig;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
* @author cdfive
* @since 1.6.0
*/
@RestController
@RequestMapping(value = "/auth", produces = MediaType.APPLICATION_JSON_VALUE)
public class AuthController {

private static Logger LOGGER = LoggerFactory.getLogger(AuthController.class);

@Value("${auth.username:sentinel}")
private String authUsername;

@Value("${auth.password:sentinel}")
private String authPassword;

@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(HttpServletRequest request, String username, String password) {
if (StringUtils.isNotBlank(DashboardConfig.getAuthUsername())) {
authUsername = DashboardConfig.getAuthUsername();
}

if (StringUtils.isNotBlank(DashboardConfig.getAuthPassword())) {
authPassword = DashboardConfig.getAuthPassword();
}

/**
* If auth.username or auth.password is blank(set in application.properties or VM arguments),
* auth will pass, as the front side validate the input which can't be blank,
* so user can input any username or password(both are not blank) to login in that case.
*/
if ( StringUtils.isNotBlank(authUsername) && !authUsername.equals(username)
|| StringUtils.isNotBlank(authPassword) && !authPassword.equals(password)) {
LOGGER.error("Login failed: Invalid username or password, username=" + username + ", password=" + password);
return Result.ofFail(-1, "Invalid username or password");
}

AuthService.AuthUser authUser = new SimpleWebAuthServiceImpl.SimpleWebAuthUserImpl(username);
request.getSession().setAttribute(SimpleWebAuthServiceImpl.WEB_SESSTION_KEY, authUser);
return Result.ofSuccess(authUser);
}

@RequestMapping(value = "/logout", method = RequestMethod.POST)
public Result logout(HttpServletRequest request) {
request.getSession().invalidate();
return Result.ofSuccess(null);
}
}

+ 118
- 0
sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/AuthFilter.java View File

@@ -0,0 +1,118 @@
/*
* 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.filter;

import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
* Servlet Filter that authenticate requests.
*
* Note:
* Some urls are excluded as they needn't auth, such as:
*
* Index url: /
* Authentication request url: /login,logout
* Used for client: /registry/machine
* Static resources: htm,html,js and so on.
*
* The excluded urls and urlSuffixes are configured in application.properties
*
* @author cdfive
* @since 1.6.0
*/
@Component
public class AuthFilter implements Filter {

private static final String URL_SUFFIX_DOT = ".";

/**Some urls which needn't auth, such as /auth/login,/registry/machine and so on*/
@Value("#{'${auth.filter.exclude-urls}'.split(',')}")
private List<String> authFilterExcludeUrls;

/**Some urls with suffixes which needn't auth, such as htm,html,js and so on*/
@Value("#{'${auth.filter.exclude-url-suffixes}'.split(',')}")
private List<String> authFilterExcludeUrlSuffixes;

/**Authentication using AuthService interface*/
@Autowired
private AuthService<HttpServletRequest> authService;

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;

String requestURI = httpRequest.getRequestURI();

// Exclude the urls which needn't auth
if (authFilterExcludeUrls.contains(requestURI)) {
chain.doFilter(request, response);
return;
}

// Exclude the urls with suffixes which needn't auth
for (String authFilterExcludeUrlSuffix : authFilterExcludeUrlSuffixes) {
if (StringUtils.isBlank(authFilterExcludeUrlSuffix)) {
continue;
}

// Add . for url suffix so that we needn't add . in property file
if (!authFilterExcludeUrlSuffix.startsWith(URL_SUFFIX_DOT)) {
authFilterExcludeUrlSuffix = URL_SUFFIX_DOT + authFilterExcludeUrlSuffix;
}

if (requestURI.endsWith(authFilterExcludeUrlSuffix)) {
chain.doFilter(request, response);
return;
}
}

AuthService.AuthUser authUser = authService.getAuthUser(httpRequest);

HttpServletResponse httpResponse = (HttpServletResponse) response;
if (authUser == null) {
// If auth fail, set response status code to 401
httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
} else {
chain.doFilter(request, response);
}
}

@Override
public void destroy() {

}
}

+ 6
- 0
sentinel-dashboard/src/main/resources/application.properties View File

@@ -8,3 +8,9 @@ logging.level.org.springframework.web=INFO
logging.file=${user.home}/logs/csp/sentinel-dashboard.log
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

#auth settings
auth.filter.exclude-urls=/,/auth/login,/auth/logout,/registry/machine
auth.filter.exclude-url-suffixes=htm,html,js,css,map,ico,ttf,woff
auth.username=sentinel
auth.password=sentinel

+ 49
- 8
sentinel-dashboard/src/main/webapp/resources/app/scripts/app.js View File

@@ -23,16 +23,57 @@ angular
'selectize',
'angularUtils.directives.dirPagination'
])
.config(['$stateProvider', '$urlRouterProvider', '$ocLazyLoadProvider',
function ($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
$ocLazyLoadProvider.config({
debug: false,
events: true,
});
.factory('AuthInterceptor', ['$window', '$state', function ($window, $state) {
var authInterceptor = {
'responseError' : function(response) {
if (response.status == 401) {
// If not auth, clear session in localStorage and jump to the login page
$window.localStorage.removeItem("session_sentinel_admin");
$state.go('login');
}

return response;
},
'response' : function(response) {
return response;
},
'request' : function(config) {
return config;
},
'requestError' : function(config){
return config;
}
};
return authInterceptor;
}])
.config(['$stateProvider', '$urlRouterProvider', '$ocLazyLoadProvider', '$httpProvider',
function ($stateProvider, $urlRouterProvider, $ocLazyLoadProvider, $httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');

$ocLazyLoadProvider.config({
debug: false,
events: true,
});

$urlRouterProvider.otherwise('/dashboard/home');
$urlRouterProvider.otherwise('/dashboard/home');

$stateProvider
.state('login', {
url: '/login',
templateUrl: 'app/views/login.html',
controller: 'LoginCtl',
resolve: {
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'sentinelDashboardApp',
files: [
'app/scripts/controllers/login.js',
]
});
}]
}
})

$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: 'app/views/dashboard/main.html',


+ 36
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/controllers/login.js View File

@@ -0,0 +1,36 @@
var app = angular.module('sentinelDashboardApp');

app.controller('LoginCtl', ['$scope', '$state', '$window', 'AuthService',
function ($scope, $state, $window, LoginService) {
// If auth, jump to the index page directly
if ($window.localStorage.getItem('session_sentinel_admin')) {
$state.go('dashboard');
}

$scope.login = function () {
if (!$scope.username) {
alert('请输入用户名');
return;
}

if (!$scope.password) {
alert('请输入密码');
return;
}

var param = {"username": $scope.username, "password": $scope.password};

LoginService.login(param).success(function (data) {
if (data.code == 0) {
$window.localStorage.setItem('session_sentinel_admin', {
username: data.data
});

$state.go('dashboard');
} else {
alert(data.msg);
}
});
};
}]
);

+ 5
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/header/header.html View File

@@ -3,6 +3,11 @@
<div class="navbar-brand">
<span style="color: #fff;font-size: 26px;">Sentinel 控制台</span>
</div>
<ul class="nav navbar-nav navbar-right">
<li>
<a href="javascript:void(0);" ng-click="logout()" style="margin: 3px 15px 0px 0px;"><span class="glyphicon glyphicon-log-out"></span>退出</a>
</li>
</ul>
</nav>
<!-- end nav -->
<sidebar></sidebar>

+ 16
- 2
sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/header/header.js View File

@@ -5,12 +5,26 @@
* # adminPosHeader
*/
angular.module('sentinelDashboardApp')
.directive('header', [function () {
.directive('header', ['AuthService', function () {
return {
templateUrl: 'app/scripts/directives/header/header.html',
restrict: 'E',
replace: true,
controller: function ($scope) {
controller: function ($scope, $state, $window, AuthService) {
if (!$window.localStorage.getItem('session_sentinel_admin')) {
$state.go('login');
}

$scope.logout = function () {
AuthService.logout().success(function (data) {
if (data.code == 0) {
$window.localStorage.removeItem("session_sentinel_admin");
$state.go('login');
} else {
alert('logout error');
}
});
}
}
}
}]);

+ 18
- 0
sentinel-dashboard/src/main/webapp/resources/app/scripts/services/auth_service.js View File

@@ -0,0 +1,18 @@
var app = angular.module('sentinelDashboardApp');

app.service('AuthService', ['$http', function ($http) {
this.login = function (param) {
return $http({
url: '/auth/login',
params: param,
method: 'POST'
})
}

this.logout = function () {
return $http({
url: '/auth/logout',
method: 'POST'
})
}
}]);

+ 29
- 0
sentinel-dashboard/src/main/webapp/resources/app/views/login.html View File

@@ -0,0 +1,29 @@
<div class="container">
<div class="row" style="margin: 200px auto 15px auto; display: table;">
<h1 id='login_title'>Sentinel控制台</h1>
</div>
<div class="row">
<div class="col-md-4" >
</div>
<div class="col-md-4">
<form class="form-horizontal">
<div class="form-group">
<label class="col-md-2 control-label">用户</label>
<div class="col-md-9">
<input class="form-control" type="text" ng-model="username" autofocus="autofocus"/>
</div>
</div>

<div class="form-group">
<label class="col-md-2 control-label">密码</label>
<div class="col-md-9">
<input class="form-control" type="password" ng-model="password" />
</div>
</div>
<div class="form-group btn-group" style="margin: 0px auto;display: table;">
<button class="btn btn-success btn-primary" ng-click="login()">登录</button>
</div>
</form>
</div>
</div>
</div>

+ 1
- 1
sentinel-dashboard/src/main/webapp/resources/dist/js/app.js
File diff suppressed because it is too large
View File


+ 1
- 1
sentinel-dashboard/src/main/webapp/resources/dist/js/app.vendor.js
File diff suppressed because it is too large
View File


+ 1
- 0
sentinel-dashboard/src/main/webapp/resources/gulpfile.js View File

@@ -43,6 +43,7 @@ const CSS_APP = [
const JS_APP = [
'app/scripts/app.js',
'app/scripts/filters/filters.js',
'app/scripts/services/auth_service.js',
'app/scripts/services/appservice.js',
'app/scripts/services/flow_service_v1.js',
'app/scripts/services/flow_service_v2.js',


+ 26
- 3
sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/config/DashboardConfigTest.java View File

@@ -24,11 +24,34 @@ import org.junit.contrib.java.lang.system.EnvironmentVariables;
public class DashboardConfigTest {
@Rule
public final EnvironmentVariables environmentVariables = new EnvironmentVariables();

@Test
public void testGetConfigStr() {
// clear cache
DashboardConfig.clearCache();

// if not set, return null
assertEquals(null, DashboardConfig.getConfigStr("a"));

// test property
System.setProperty("a", "111");
assertEquals("111", DashboardConfig.getConfigStr("a"));

// test env
environmentVariables.set("a", "222");
// return value in cache
assertEquals("111", DashboardConfig.getConfigStr("a"));

// clear cache and then test
DashboardConfig.clearCache();
assertEquals("222", DashboardConfig.getConfigStr("a"));
}

@Test
public void testGetConfigInt() {
// skip cache
// clear cache
DashboardConfig.clearCache();

// default value
assertEquals(0, DashboardConfig.getConfigInt("t", 0, 10));
DashboardConfig.clearCache();


Loading…
Cancel
Save