mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-10 11:40:01 +08:00
* [ISSUE #348] fix Some interaction issues with the consumer interface * commit * [ISSUE #353] fix Actuator vulnerability issues * [ISSUE #353] fix Actuator vulnerability issues * commit
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const appConfig = {
|
const appConfig = {
|
||||||
apiBaseUrl: 'http://localhost:8082'
|
apiBaseUrl: 'http://localhost:8082'
|
||||||
};
|
};
|
||||||
@@ -33,29 +34,73 @@ const remoteApi = {
|
|||||||
return `${appConfig.apiBaseUrl}/${endpoint}`;
|
return `${appConfig.apiBaseUrl}/${endpoint}`;
|
||||||
},
|
},
|
||||||
|
|
||||||
_fetch: async (url, options) => {
|
|
||||||
|
async getCsrfToken() {
|
||||||
|
const csrfToken = this.getCookie();
|
||||||
|
|
||||||
|
if (csrfToken) {
|
||||||
|
return csrfToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(remoteApi.buildUrl("/rocketmq-dashboard/csrf-token"), {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include'
|
||||||
|
});
|
||||||
|
|
||||||
|
const newCsrfToken = this.getCookie();
|
||||||
|
if (!newCsrfToken) {
|
||||||
|
console.error("Failed to get CSRF Token");
|
||||||
|
throw new Error("CSRF Token not available");
|
||||||
|
}
|
||||||
|
return newCsrfToken;
|
||||||
|
},
|
||||||
|
|
||||||
|
getCookie() {
|
||||||
|
return document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1')
|
||||||
|
},
|
||||||
|
|
||||||
|
_fetch: async (url, options = {}) => {
|
||||||
|
const headers = {
|
||||||
|
...options.headers,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const csrfToken = await remoteApi.getCsrfToken();
|
||||||
|
console.log(csrfToken)
|
||||||
|
if (!csrfToken) {
|
||||||
|
console.warn('CSRF Token not found');
|
||||||
|
}else{
|
||||||
|
headers["X-XSRF-TOKEN"] = csrfToken;
|
||||||
|
}
|
||||||
|
console.log(csrfToken)
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 在 options 中添加 credentials: 'include'
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
...options, // 保留原有的 options
|
...options,
|
||||||
credentials: 'include' // 关键改动:允许发送 Cookie
|
headers,
|
||||||
|
credentials: 'include',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// 检查响应是否被重定向,并且最终的 URL 包含了登录页的路径。
|
|
||||||
// 这是会话过期或需要认证时后端重定向到登录页的常见模式。
|
|
||||||
// 注意:fetch 会自动跟随 GET 请求的 3xx 重定向,所以我们检查的是 response.redirected。
|
|
||||||
if (response.redirected) {
|
if (response.redirected) {
|
||||||
if (_redirectHandler) {
|
if (_redirectHandler) {
|
||||||
_redirectHandler(); // 如果设置了重定向处理函数,则调用它
|
_redirectHandler();
|
||||||
}
|
}
|
||||||
return {__isRedirectHandled: true};
|
return {__isRedirectHandled: true};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(response.status == 403){
|
||||||
|
window.localStorage.removeItem("csrfToken");
|
||||||
|
console.log(111)
|
||||||
|
await remoteApi.getCsrfToken()
|
||||||
|
}
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fetch 请求出错:", error);
|
console.error('fetch error:', error);
|
||||||
throw error;
|
window.localStorage.removeItem("csrfToken");
|
||||||
|
console.log(111)
|
||||||
|
await remoteApi.getCsrfToken()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -232,24 +277,19 @@ const remoteApi = {
|
|||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 假设服务器总是返回 JSON
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// 1. 打开一个新的空白窗口
|
|
||||||
const newWindow = window.open('', '_blank');
|
const newWindow = window.open('', '_blank');
|
||||||
|
|
||||||
if (!newWindow) {
|
if (!newWindow) {
|
||||||
// 浏览器可能会阻止弹窗,需要用户允许
|
|
||||||
return {status: 1, errMsg: "Failed to open new window. Please allow pop-ups for this site."};
|
return {status: 1, errMsg: "Failed to open new window. Please allow pop-ups for this site."};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 将 JSON 数据格式化后写入新窗口
|
|
||||||
newWindow.document.write('<html><head><title>DLQ 导出内容</title></head><body>');
|
newWindow.document.write('<html><head><title>DLQ 导出内容</title></head><body>');
|
||||||
newWindow.document.write('<h1>DLQ 导出 JSON 内容</h1>');
|
newWindow.document.write('<h1>DLQ 导出 JSON 内容</h1>');
|
||||||
// 使用 <pre> 标签保持格式,并使用 JSON.stringify 格式化 JSON 以便于阅读
|
|
||||||
newWindow.document.write('<pre>' + JSON.stringify(data, null, 2) + '</pre>');
|
newWindow.document.write('<pre>' + JSON.stringify(data, null, 2) + '</pre>');
|
||||||
newWindow.document.write('</body></html>');
|
newWindow.document.write('</body></html>');
|
||||||
newWindow.document.close(); // 关闭文档流,确保内容显示
|
newWindow.document.close();
|
||||||
|
|
||||||
return {status: 0, msg: "导出请求成功,内容已在新页面显示"};
|
return {status: 0, msg: "导出请求成功,内容已在新页面显示"};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -382,6 +422,9 @@ const remoteApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
queryConsumerGroupList: async (skipSysGroup, address) => {
|
queryConsumerGroupList: async (skipSysGroup, address) => {
|
||||||
|
if (address === undefined) {
|
||||||
|
address = ""
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}&address=${address}`));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/groupList.query?skipSysGroup=${skipSysGroup}&address=${address}`));
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -404,9 +447,12 @@ const remoteApi = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshAllConsumerGroup: async () => {
|
refreshAllConsumerGroup: async (address) => {
|
||||||
|
if (address === undefined) {
|
||||||
|
address = ""
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl("/consumer/group.refresh.all"));
|
const response = await remoteApi._fetch(remoteApi.buildUrl(`/consumer/group.refresh.all?address=${address}`));
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -875,21 +921,17 @@ const remoteApi = {
|
|||||||
login: async (username, password) => {
|
login: async (username, password) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
// 2. 发送请求,注意 body 可以是空字符串或 null,或者直接省略 body
|
|
||||||
// 这里使用 GET 方法,因为参数在 URL 上
|
|
||||||
const response = await remoteApi._fetch(remoteApi.buildUrl("/login/login.do"), {
|
const response = await remoteApi._fetch(remoteApi.buildUrl("/login/login.do"), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: password
|
||||||
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded' // 这个 header 可能不再需要,或者需要调整
|
'Content-Type': 'application/json'
|
||||||
},
|
}
|
||||||
body: new URLSearchParams({
|
|
||||||
username: username, // 假设 username 是变量名
|
|
||||||
password: password // 假设 password 是变量名
|
|
||||||
}).toString()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. 处理响应
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@@ -38,6 +38,7 @@ const ClientInfoModal = ({visible, group, address, onCancel, messageApi}) => {
|
|||||||
setConnectionData(connResponse.data);
|
setConnectionData(connResponse.data);
|
||||||
}else{
|
}else{
|
||||||
messageApi.error(connResponse.errMsg);
|
messageApi.error(connResponse.errMsg);
|
||||||
|
setConnectionData(null);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@@ -270,7 +270,7 @@ const ConsumerGroupList = () => {
|
|||||||
|
|
||||||
const handleRefreshConsumerData = async () => {
|
const handleRefreshConsumerData = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const refreshResult = await remoteApi.refreshAllConsumerGroup();
|
const refreshResult = await remoteApi.refreshAllConsumerGroup(selectedProxy);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
if (refreshResult && refreshResult.status === 0) {
|
if (refreshResult && refreshResult.status === 0) {
|
||||||
|
@@ -20,7 +20,6 @@ import {defaultTheme, themes} from '../../assets/styles/theme';
|
|||||||
import {setTheme} from '../actions/themeActions';
|
import {setTheme} from '../actions/themeActions';
|
||||||
|
|
||||||
export const useTheme = () => {
|
export const useTheme = () => {
|
||||||
// 从 Redux store 中取出 currentThemeName
|
|
||||||
const currentThemeName = useSelector(state => state.theme.currentThemeName);
|
const currentThemeName = useSelector(state => state.theme.currentThemeName);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
@@ -28,7 +28,6 @@ const initialState = {
|
|||||||
const themeReducer = (state = initialState, action) => {
|
const themeReducer = (state = initialState, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case SET_THEME:
|
case SET_THEME:
|
||||||
// 注意:reducer 应该返回新的状态对象,而不是直接修改旧状态
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
currentThemeName: action.payload,
|
currentThemeName: action.payload,
|
||||||
|
5
pom.xml
5
pom.xml
@@ -149,6 +149,11 @@
|
|||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
<artifactId>spring-boot-starter-validation</artifactId>
|
||||||
<version>${spring.boot.version}</version>
|
<version>${spring.boot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
<version>${spring.boot.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-collections</groupId>
|
<groupId>commons-collections</groupId>
|
||||||
<artifactId>commons-collections</artifactId>
|
<artifactId>commons-collections</artifactId>
|
||||||
|
@@ -31,7 +31,6 @@ import org.springframework.web.context.request.NativeWebRequest;
|
|||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
@@ -90,17 +89,6 @@ public class AuthWebMVCConfigurerAdapter implements WebMvcConfigurer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
|
|
||||||
registry.addMapping("/**")
|
|
||||||
.allowedOriginPatterns("http://localhost:3003")
|
|
||||||
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
|
|
||||||
.maxAge(3600)
|
|
||||||
.allowCredentials(true)
|
|
||||||
.allowedHeaders("content-type", "Authorization", "X-Requested-With", "Origin", "Accept")
|
|
||||||
.exposedHeaders("authorization");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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 org.apache.rocketmq.dashboard.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.springframework.security.config.Customizer.withDefaults;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class SecurityConfig {
|
||||||
|
@Bean
|
||||||
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.cors(withDefaults())
|
||||||
|
.csrf(csrf -> csrf
|
||||||
|
.ignoringRequestMatchers("/actuator/**")
|
||||||
|
.ignoringRequestMatchers("/rocketmq-dashboard/csrf-token")
|
||||||
|
.csrfTokenRepository(csrfTokenRepository())
|
||||||
|
.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
|
||||||
|
)
|
||||||
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
|
.requestMatchers("/actuator/**").hasRole("ADMIN")
|
||||||
|
.anyRequest().permitAll()
|
||||||
|
)
|
||||||
|
.httpBasic(withDefaults());
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CorsConfigurationSource corsConfigurationSource() {
|
||||||
|
CorsConfiguration configuration = new CorsConfiguration();
|
||||||
|
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3003"));
|
||||||
|
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||||
|
configuration.setAllowedHeaders(Arrays.asList("content-type", "Authorization", "X-Requested-With", "Origin", "Accept", "X-XSRF-TOKEN"));
|
||||||
|
configuration.setAllowCredentials(true);
|
||||||
|
configuration.setMaxAge(3600L);
|
||||||
|
|
||||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
public CsrfTokenRepository csrfTokenRepository() {
|
||||||
|
return CookieCsrfTokenRepository.withHttpOnlyFalse();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You 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 org.apache.rocketmq.dashboard.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = "/rocketmq-dashboard")
|
||||||
|
public class CsrfTokenController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CsrfTokenRepository csrfTokenRepository;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/csrf-token", method = RequestMethod.GET)
|
||||||
|
@ResponseBody
|
||||||
|
public Object getCsrfToken(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
CsrfToken token = csrfTokenRepository.generateToken(request);
|
||||||
|
csrfTokenRepository.saveToken(token, request, response);
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
}
|
@@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@@ -65,7 +66,7 @@ public class LoginController {
|
|||||||
|
|
||||||
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
|
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public Object login(org.apache.rocketmq.remoting.protocol.body.UserInfo userInfoRequest,
|
public Object login(@RequestBody org.apache.rocketmq.remoting.protocol.body.UserInfo userInfoRequest,
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
HttpServletResponse response) throws Exception {
|
HttpServletResponse response) throws Exception {
|
||||||
logger.info("user:{} login", userInfoRequest.getUsername());
|
logger.info("user:{} login", userInfoRequest.getUsername());
|
||||||
|
@@ -33,6 +33,12 @@ public class AuthInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (request.getRequestURL().toString().contains("/rocketmq-dashboard/csrf-token")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return loginService.login(request, response);
|
return loginService.login(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -135,6 +135,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_PERMISSION_GROUP);
|
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_PERMISSION_GROUP);
|
||||||
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_OWNER_GROUP);
|
SYSTEM_GROUP_SET.add(MixAll.CID_ONSAPI_OWNER_GROUP);
|
||||||
SYSTEM_GROUP_SET.add(MixAll.CID_SYS_RMQ_TRANS);
|
SYSTEM_GROUP_SET.add(MixAll.CID_SYS_RMQ_TRANS);
|
||||||
|
SYSTEM_GROUP_SET.add("CID_DefaultHeartBeatSyncerTopic");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -147,7 +148,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
if (cacheConsumeInfoList.isEmpty() && !isCacheBeingBuilt) {
|
if (cacheConsumeInfoList.isEmpty() && !isCacheBeingBuilt) {
|
||||||
isCacheBeingBuilt = true;
|
isCacheBeingBuilt = true;
|
||||||
try {
|
try {
|
||||||
makeGroupListCache();
|
makeGroupListCache(address);
|
||||||
} finally {
|
} finally {
|
||||||
isCacheBeingBuilt = false;
|
isCacheBeingBuilt = false;
|
||||||
}
|
}
|
||||||
@@ -173,7 +174,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void makeGroupListCache() {
|
public void makeGroupListCache(String address) {
|
||||||
SubscriptionGroupWrapper subscriptionGroupWrapper = null;
|
SubscriptionGroupWrapper subscriptionGroupWrapper = null;
|
||||||
try {
|
try {
|
||||||
ClusterInfo clusterInfo = clusterInfoService.get();
|
ClusterInfo clusterInfo = clusterInfoService.get();
|
||||||
@@ -205,7 +206,7 @@ public class ConsumerServiceImpl extends AbstractCommonService implements Consum
|
|||||||
String consumerGroup = entry.getKey();
|
String consumerGroup = entry.getKey();
|
||||||
executorService.submit(() -> {
|
executorService.submit(() -> {
|
||||||
try {
|
try {
|
||||||
GroupConsumeInfo consumeInfo = queryGroup(consumerGroup, "");
|
GroupConsumeInfo consumeInfo = queryGroup(consumerGroup, address);
|
||||||
consumeInfo.setAddress(entry.getValue());
|
consumeInfo.setAddress(entry.getValue());
|
||||||
if (SYSTEM_GROUP_SET.contains(consumerGroup)) {
|
if (SYSTEM_GROUP_SET.contains(consumerGroup)) {
|
||||||
consumeInfo.setSubGroupType("SYSTEM");
|
consumeInfo.setSubGroupType("SYSTEM");
|
||||||
|
@@ -33,6 +33,18 @@ spring:
|
|||||||
application:
|
application:
|
||||||
name: rocketmq-dashboard
|
name: rocketmq-dashboard
|
||||||
|
|
||||||
|
security:
|
||||||
|
user:
|
||||||
|
name: rocketmq
|
||||||
|
password: 1234567
|
||||||
|
roles: ADMIN
|
||||||
|
|
||||||
|
management:
|
||||||
|
endpoints:
|
||||||
|
web:
|
||||||
|
exposure:
|
||||||
|
include: "*"
|
||||||
|
|
||||||
logging:
|
logging:
|
||||||
config: classpath:logback.xml
|
config: classpath:logback.xml
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user