mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2026-02-21 04:45:41 +08:00
* [ISSUE #5]Add permission control when loginRequired is true. * optimize the code * Wildcard characters are supported * add Apache License headers Co-authored-by: zhangjidi2016 <zhangjidi@cmss.chinamobile.com>
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ClusterService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -27,6 +28,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/cluster")
|
||||
@Permission
|
||||
public class ClusterController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.ConsumerConfigInfo;
|
||||
import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ConsumerService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.slf4j.Logger;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/consumer")
|
||||
@Permission
|
||||
public class ConsumerController {
|
||||
private Logger logger = LoggerFactory.getLogger(ConsumerController.class);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.DashboardService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/dashboard")
|
||||
@Permission
|
||||
public class DashboardController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.apache.rocketmq.common.protocol.body.ConsumeMessageDirectlyResult;
|
||||
import org.apache.rocketmq.dashboard.model.MessagePage;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MessageService;
|
||||
import org.apache.rocketmq.dashboard.util.JsonUtil;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
@@ -41,6 +42,7 @@ import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/message")
|
||||
@Permission
|
||||
public class MessageController {
|
||||
private Logger logger = LoggerFactory.getLogger(MessageController.class);
|
||||
@Resource
|
||||
|
||||
@@ -26,6 +26,7 @@ import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.Pair;
|
||||
import org.apache.rocketmq.dashboard.model.MessageView;
|
||||
import org.apache.rocketmq.dashboard.model.trace.MessageTraceGraph;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MessageService;
|
||||
import org.apache.rocketmq.dashboard.service.MessageTraceService;
|
||||
import org.apache.rocketmq.tools.admin.api.MessageTrack;
|
||||
@@ -37,6 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/messageTrace")
|
||||
@Permission
|
||||
public class MessageTraceController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.model.ConsumerMonitorConfig;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.MonitorService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/monitor")
|
||||
@Permission
|
||||
public class MonitorController {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MonitorController.class);
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.aspect.admin.annotation.OriginalControllerReturnValue;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/rocketmq")
|
||||
@Permission
|
||||
public class NamesvrController {
|
||||
@Resource
|
||||
private OpsService opsService;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.OpsService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/ops")
|
||||
@Permission
|
||||
public class OpsController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.apache.rocketmq.dashboard.controller;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.common.protocol.body.ProducerConnection;
|
||||
import org.apache.rocketmq.dashboard.model.ConnectionInfo;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.dashboard.service.ProducerService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/producer")
|
||||
@Permission
|
||||
public class ProducerController {
|
||||
|
||||
@Resource
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.apache.rocketmq.dashboard.controller;
|
||||
|
||||
import org.apache.rocketmq.client.exception.MQClientException;
|
||||
import org.apache.rocketmq.dashboard.permisssion.Permission;
|
||||
import org.apache.rocketmq.remoting.exception.RemotingException;
|
||||
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
|
||||
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
|
||||
@@ -38,6 +39,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/topic")
|
||||
@Permission
|
||||
public class TopicController {
|
||||
private Logger logger = LoggerFactory.getLogger(TopicController.class);
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.permisssion;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Permission {
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.permisssion;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.service.PermissionService;
|
||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@Aspect
|
||||
@Component
|
||||
public class PermissionAspect {
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
|
||||
/**
|
||||
* @Permission can be applied to the Controller class to implement Permission verification on all methods in the class
|
||||
* can also be applied to methods in a class for fine control
|
||||
*/
|
||||
@Pointcut("@annotation(org.apache.rocketmq.dashboard.permisssion.Permission) || @within(org.apache.rocketmq.dashboard.permisssion.Permission)")
|
||||
private void permission() {
|
||||
|
||||
}
|
||||
|
||||
@Around("permission()")
|
||||
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
if (configure.isLoginRequired()) {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
String url = request.getRequestURI();
|
||||
UserInfo userInfo = (UserInfo) request.getSession().getAttribute(WebUtil.USER_INFO);
|
||||
if (userInfo == null || userInfo.getUser() == null) {
|
||||
throw new ServiceException(-1, "user not login");
|
||||
}
|
||||
boolean checkResult = permissionService.checkUrlAvailable(userInfo, url);
|
||||
if (!checkResult) {
|
||||
throw new ServiceException(-1, "no permission");
|
||||
}
|
||||
}
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.permisssion;
|
||||
|
||||
public enum UserRoleEnum {
|
||||
ADMIN(1, "admin"),
|
||||
ORDINARY(0, "ordinary");
|
||||
|
||||
private int roleType;
|
||||
private String roleName;
|
||||
|
||||
UserRoleEnum(int roleType, String roleName) {
|
||||
this.roleType = roleType;
|
||||
this.roleName = roleName;
|
||||
}
|
||||
|
||||
public int getRoleType() {
|
||||
return roleType;
|
||||
}
|
||||
|
||||
public String getRoleName() {
|
||||
return roleName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.service;
|
||||
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
|
||||
public interface PermissionService {
|
||||
|
||||
boolean checkUrlAvailable(UserInfo userInfo, String url);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.service.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.srvutil.FileWatchService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractFileStore {
|
||||
public final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
public String filePath;
|
||||
|
||||
public AbstractFileStore(RMQConfigure configure, String fileName) {
|
||||
filePath = configure.getRocketMqDashboardDataPath() + File.separator + fileName;
|
||||
if (!new File(filePath).exists()) {
|
||||
// Use the default path
|
||||
InputStream inputStream = getClass().getResourceAsStream("/" + fileName);
|
||||
if (inputStream == null) {
|
||||
log.error(String.format("Can not found the file %s in Spring Boot jar", fileName));
|
||||
System.exit(1);
|
||||
} else {
|
||||
try {
|
||||
load(inputStream);
|
||||
} catch (Exception e) {
|
||||
log.error("fail to load file {}", filePath, e);
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
log.error("inputStream close exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.info(String.format("configure file is %s", filePath));
|
||||
load();
|
||||
watch();
|
||||
}
|
||||
}
|
||||
|
||||
abstract void load(InputStream inputStream);
|
||||
|
||||
private void load() {
|
||||
load(null);
|
||||
}
|
||||
|
||||
private boolean watch() {
|
||||
try {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[] {filePath}, new FileWatchService.Listener() {
|
||||
@Override
|
||||
public void onChanged(String path) {
|
||||
log.info("The file changed, reload the context");
|
||||
load();
|
||||
}
|
||||
});
|
||||
fileWatchService.start();
|
||||
log.info("Succeed to start FileWatcherService");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start FileWatcherService", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Resource;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.UserInfo;
|
||||
import org.apache.rocketmq.dashboard.service.PermissionService;
|
||||
import org.apache.rocketmq.dashboard.util.MatcherUtil;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ADMIN;
|
||||
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ORDINARY;
|
||||
|
||||
@Service
|
||||
public class PermissionServiceImpl implements PermissionService, InitializingBean {
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private PermissionFileStore permissionFileStore;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (configure.isLoginRequired()) {
|
||||
permissionFileStore = new PermissionFileStore(configure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkUrlAvailable(UserInfo userInfo, String url) {
|
||||
int type = userInfo.getUser().getType();
|
||||
// if it is admin, it could access all resources
|
||||
if (type == ADMIN.getRoleType()) {
|
||||
return true;
|
||||
}
|
||||
String loginUserRole = ORDINARY.getRoleName();
|
||||
Map<String, List<String>> rolePerms = PermissionFileStore.rolePerms;
|
||||
List<String> perms = rolePerms.get(loginUserRole);
|
||||
for (String perm : perms) {
|
||||
if (MatcherUtil.match(perm, url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class PermissionFileStore extends AbstractFileStore {
|
||||
private static final String FILE_NAME = "role-permission.yml";
|
||||
|
||||
private static Map<String/**role**/, List<String>/**accessUrls**/> rolePerms = new ConcurrentHashMap<>();
|
||||
|
||||
public PermissionFileStore(RMQConfigure configure) {
|
||||
super(configure, FILE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(InputStream inputStream) {
|
||||
Yaml yaml = new Yaml();
|
||||
JSONObject rolePermsData = null;
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
rolePermsData = yaml.loadAs(new FileReader(filePath), JSONObject.class);
|
||||
} else {
|
||||
rolePermsData = yaml.loadAs(inputStream, JSONObject.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("load user-permission.yml failed", e);
|
||||
throw new ServiceException(0, String.format("Failed to load rolePermission property file: %s", filePath));
|
||||
}
|
||||
rolePerms.clear();
|
||||
rolePerms.putAll(rolePermsData.getObject("rolePerms", Map.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,15 +21,11 @@ import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.service.UserService;
|
||||
import org.apache.rocketmq.srvutil.FileWatchService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
@@ -40,9 +36,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService, InitializingBean {
|
||||
@Resource
|
||||
RMQConfigure configure;
|
||||
private RMQConfigure configure;
|
||||
|
||||
FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||
private FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||
|
||||
@Override
|
||||
public User queryByName(String name) {
|
||||
@@ -61,40 +57,17 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileBasedUserInfoStore {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
public static class FileBasedUserInfoStore extends AbstractFileStore {
|
||||
private static final String FILE_NAME = "users.properties";
|
||||
|
||||
private String filePath;
|
||||
private final Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
public FileBasedUserInfoStore(RMQConfigure configure) {
|
||||
filePath = configure.getRocketMqDashboardDataPath() + File.separator + FILE_NAME;
|
||||
if (!new File(filePath).exists()) {
|
||||
//Use the default path
|
||||
InputStream inputStream = getClass().getResourceAsStream("/" + FILE_NAME);
|
||||
if (inputStream == null) {
|
||||
log.error(String.format("Can not found the file %s in Spring Boot jar", FILE_NAME));
|
||||
System.out.printf(String.format("Can not found file %s in Spring Boot jar or %s, stop the dashboard starting",
|
||||
FILE_NAME, configure.getRocketMqDashboardDataPath()));
|
||||
System.exit(1);
|
||||
} else {
|
||||
load(inputStream);
|
||||
}
|
||||
} else {
|
||||
log.info(String.format("Login Users configure file is %s", filePath));
|
||||
load();
|
||||
watch();
|
||||
}
|
||||
super(configure, FILE_NAME);
|
||||
}
|
||||
|
||||
private void load() {
|
||||
load(null);
|
||||
}
|
||||
|
||||
private void load(InputStream inputStream) {
|
||||
|
||||
@Override
|
||||
public void load(InputStream inputStream) {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
@@ -112,7 +85,8 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
int role;
|
||||
for (String key : prop.stringPropertyNames()) {
|
||||
String v = prop.getProperty(key);
|
||||
if (v == null) continue;
|
||||
if (v == null)
|
||||
continue;
|
||||
arrs = v.split(",", 2);
|
||||
if (arrs.length == 0) {
|
||||
continue;
|
||||
@@ -125,30 +99,10 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
loadUserMap.put(key, new User(key, arrs[0].trim(), role));
|
||||
}
|
||||
|
||||
|
||||
userMap.clear();
|
||||
userMap.putAll(loadUserMap);
|
||||
}
|
||||
|
||||
private boolean watch() {
|
||||
try {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[]{filePath}, new FileWatchService.Listener() {
|
||||
@Override
|
||||
public void onChanged(String path) {
|
||||
log.info("The loginUserInfo property file changed, reload the context");
|
||||
load();
|
||||
}
|
||||
});
|
||||
fileWatchService.start();
|
||||
log.info("Succeed to start LoginUserWatcherService");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start LoginUserWatcherService", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public User queryByName(String name) {
|
||||
return userMap.get(name);
|
||||
}
|
||||
@@ -158,7 +112,6 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
if (user != null && password.equals(user.getPassword())) {
|
||||
return user.cloneOne();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,12 @@ public class GlobalExceptionHandler {
|
||||
public JsonResult<Object> jsonErrorHandler(HttpServletRequest req, Exception ex) throws Exception {
|
||||
JsonResult<Object> value = null;
|
||||
if (ex != null) {
|
||||
logger.error("op=global_exception_handler_print_error", ex);
|
||||
if (ex instanceof ServiceException) {
|
||||
logger.error("Occur service exception: {}", ex.getMessage());
|
||||
value = new JsonResult<Object>(((ServiceException) ex).getCode(), ex.getMessage());
|
||||
}
|
||||
else {
|
||||
logger.error("op=global_exception_handler_print_error", ex);
|
||||
value = new JsonResult<Object>(-1, ex.getMessage() == null ? ex.toString() : ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MatcherUtil {
|
||||
|
||||
public static boolean match(String accessUrl, String reqPath) {
|
||||
String regPath = getRegPath(accessUrl);
|
||||
return Pattern.compile(regPath).matcher(reqPath).matches();
|
||||
}
|
||||
|
||||
private static String getRegPath(String path) {
|
||||
char[] chars = path.toCharArray();
|
||||
int len = chars.length;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean preX = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (chars[i] == '*') {
|
||||
if (preX) {
|
||||
sb.append(".*");
|
||||
preX = false;
|
||||
} else if (i + 1 == len) {
|
||||
sb.append("[^/]*");
|
||||
} else {
|
||||
preX = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (preX) {
|
||||
sb.append("[^/]*");
|
||||
preX = false;
|
||||
}
|
||||
if (chars[i] == '?') {
|
||||
sb.append('.');
|
||||
} else {
|
||||
sb.append(chars[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user