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
This commit is contained in:
parent
7d344dcb95
commit
4acb907050
|
|
@ -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 参数的含义是:
|
||||
|
||||
| 参数 | 作用 |
|
||||
|
|
|
|||
|
|
@ -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 | 主机失联判定,不可关闭
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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');
|
||||
}
|
||||
|
||||
$urlRouterProvider.otherwise('/dashboard/home');
|
||||
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');
|
||||
|
||||
$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',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
};
|
||||
}]
|
||||
);
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}]);
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
})
|
||||
}
|
||||
}]);
|
||||
|
|
@ -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>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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…
Reference in New Issue