mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-10 11:40:01 +08:00
[ISSUE-205|247] Support SSL + Login: Polish with testcase, doc, session over cookie
This commit is contained in:
@@ -61,4 +61,55 @@
|
||||
* 根据Topic和Key进行查询
|
||||
* 最多只会展示64条
|
||||
* 根据消息主题和消息Id进行消息的查询
|
||||
* 消息详情可以展示这条消息的详细信息,查看消息对应到具体消费组的消费情况(如果异常,可以查看具体的异常信息)。可以向指定的消费组重发消息。
|
||||
* 消息详情可以展示这条消息的详细信息,查看消息对应到具体消费组的消费情况(如果异常,可以查看具体的异常信息)。可以向指定的消费组重发消息。
|
||||
|
||||
|
||||
## HTTPS 方式访问Console
|
||||
* HTTPS功能实际上是使用SpringBoot提供的配置功能即可完成,首先,需要有一个SSL KeyStore来存放服务端证书,可以使用本工程所提供的测试密钥库:
|
||||
resources/rmqcngkeystore.jks, 它可以通过如下keytool命令生成
|
||||
```
|
||||
#生成库并以rmqcngKey别名添加秘钥
|
||||
keytool -genkeypair -alias rmqcngKey -keyalg RSA -validity 3650 -keystore rmqcngkeystore.jks
|
||||
#查看keystore内容
|
||||
keytool -list -v -keystore rmqcngkeystore.jks
|
||||
#转换库格式
|
||||
keytool -importkeystore -srckeystore rmqcngkeystore.jks -destkeystore rmqcngkeystore.jks -deststoretype pkcs12
|
||||
```
|
||||
|
||||
* 配置resources/application.properties, 打开SSL的相关选项, 启动console后即开启了HTTPS.
|
||||
```
|
||||
#设置https端口
|
||||
server.port=8443
|
||||
|
||||
### SSL setting
|
||||
#server.ssl.key-store=classpath:rmqcngkeystore.jks
|
||||
#server.ssl.key-store-password=rocketmq
|
||||
#server.ssl.keyStoreType=PKCS12
|
||||
#server.ssl.keyAlias=rmqcngkey
|
||||
```
|
||||
|
||||
## 登录访问Console
|
||||
在访问Console时支持按用户名和密码登录控制台,在操作完成后登出。需要做如下的设置:
|
||||
|
||||
* 1.在Spring配置文件resources/application.properties中修改 开启登录功能
|
||||
```$xslt
|
||||
# 开启登录功能
|
||||
rocketmq.config.loginRequired=true
|
||||
|
||||
# Dashboard文件目录,登录用户配置文件所在目录
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
```
|
||||
* 2.确保${rocketmq.config.dataPath}定义的目录存在,并且该目录下创建登录配置文件"users.properties", 如果该目录下不存在此文件,则默认使用resources/users.properties文件。
|
||||
users.properties文件格式为:
|
||||
```$xslt
|
||||
# 该文件支持热修改,即添加和修改用户时,不需要重新启动console
|
||||
# 格式, 每行定义一个用户, username=password[,N] #N是可选项,可以为0 (普通用户); 1 (管理员)
|
||||
|
||||
#定义管理员
|
||||
admin=admin,1
|
||||
|
||||
#定义普通用户
|
||||
user1=user1
|
||||
user2=user2
|
||||
```
|
||||
* 3. 启动控制台则开启了登录功能
|
@@ -62,4 +62,57 @@
|
||||
* Only Return 64 Messages
|
||||
* Query By Topic And MessageId
|
||||
* look over this message's detail info.you can see the message's consume state(each group has one line),show the exception message if has exception.
|
||||
you can send this message to the group you selected
|
||||
you can send this message to the group you selected
|
||||
|
||||
|
||||
## Access Console with HTTPS
|
||||
* SpringBoot itself has provided the SSL configuration. You can use the project test Keystore:resources/rmqcngkeystore.jks. The store is generated with the following unix keytool commands:
|
||||
```
|
||||
#Generate Keystore and add alias rmqcngKey
|
||||
keytool -genkeypair -alias rmqcngKey -keyalg RSA -validity 3650 -keystore rmqcngkeystore.jks
|
||||
#View keystore content
|
||||
keytool -list -v -keystore rmqcngkeystore.jks
|
||||
#Transfer type as official
|
||||
keytool -importkeystore -srckeystore rmqcngkeystore.jks -destkeystore rmqcngkeystore.jks -deststoretype pkcs12
|
||||
```
|
||||
|
||||
* Uncomment the following SSL properties in resources/application.properties. restart Console then access with HTTPS.
|
||||
|
||||
```
|
||||
#Set https port
|
||||
server.port=8443
|
||||
|
||||
### SSL setting
|
||||
server.ssl.key-store=classpath:rmqcngkeystore.jks
|
||||
server.ssl.key-store-password=rocketmq
|
||||
server.ssl.keyStoreType=PKCS12
|
||||
server.ssl.keyAlias=rmqcngkey
|
||||
```
|
||||
|
||||
## Login/Logout on Console
|
||||
Access Console with username and password and logout to leave the console。To stage the function on, we need the steps below:
|
||||
|
||||
* 1.Turn on the property in resources/application.properties.
|
||||
```$xslt
|
||||
# open the login func
|
||||
rocketmq.config.loginRequired=true
|
||||
|
||||
# Directory of ashboard & login user configure file
|
||||
rocketmq.config.dataPath=/tmp/rocketmq-console/data
|
||||
```
|
||||
* 2.Make sure the directory defined in property ${rocketmq.config.dataPath} exists and the file "users.properties" is created under it.
|
||||
The console system will use the resources/users.properties by default if a customized file is not found。
|
||||
|
||||
The format in the content of users.properties:
|
||||
```$xslt
|
||||
# This file supports hot change, any change will be auto-reloaded without Console restarting.
|
||||
# Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin)
|
||||
|
||||
# Define Admin
|
||||
admin=admin,1
|
||||
|
||||
# Define Normal users
|
||||
user1=user1
|
||||
user2=user2
|
||||
```
|
||||
* 3. Restart Console Application after above configuration setting well.
|
@@ -33,7 +33,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@@ -64,7 +64,7 @@ public class AuthWebMVCConfigurerAdapter extends WebMvcConfigurerAdapter {
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,
|
||||
NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getAttribute((ServletRequest) nativeWebRequest.getNativeRequest(),
|
||||
UserInfo userInfo = (UserInfo) WebUtil.getValueFromSession((HttpServletRequest) nativeWebRequest.getNativeRequest(),
|
||||
UserInfo.USER_INFO);
|
||||
if (userInfo != null) {
|
||||
return userInfo;
|
||||
|
@@ -17,15 +17,12 @@
|
||||
package org.apache.rocketmq.console.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.common.MixAll;
|
||||
import org.apache.rocketmq.console.util.CipherHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
|
||||
@@ -47,19 +44,8 @@ public class RMQConfigure {
|
||||
|
||||
private String msgTrackTopicName;
|
||||
|
||||
private String ciperKey = "rocketmqrocketmq";
|
||||
|
||||
private boolean loginRequired = false;
|
||||
|
||||
public String getCiperKey() {
|
||||
return ciperKey;
|
||||
}
|
||||
|
||||
public void setCiperKey(String ciperKey) {
|
||||
this.ciperKey = ciperKey;
|
||||
}
|
||||
|
||||
|
||||
public String getNamesrvAddr() {
|
||||
return namesrvAddr;
|
||||
}
|
||||
@@ -112,12 +98,6 @@ public class RMQConfigure {
|
||||
this.msgTrackTopicName = msgTrackTopicName;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CipherHelper cipherHelper() throws UnsupportedEncodingException {
|
||||
CipherHelper cipherHelper = new CipherHelper(getCiperKey());
|
||||
return cipherHelper;
|
||||
}
|
||||
|
||||
public boolean isLoginRequired() {
|
||||
return loginRequired;
|
||||
}
|
||||
|
@@ -17,9 +17,10 @@
|
||||
|
||||
package org.apache.rocketmq.console.controller;
|
||||
|
||||
import org.apache.rocketmq.console.config.RMQConfigure;
|
||||
import org.apache.rocketmq.console.model.User;
|
||||
import org.apache.rocketmq.console.model.UserInfo;
|
||||
import org.apache.rocketmq.console.service.UserService;
|
||||
import org.apache.rocketmq.console.util.CipherHelper;
|
||||
import org.apache.rocketmq.console.util.WebUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -30,29 +31,33 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/login")
|
||||
public class LoginController {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private CipherHelper cipherHelper;
|
||||
|
||||
@RequestMapping(value = "/index", method = RequestMethod.GET)
|
||||
public String index(Map<String, Object> map) {
|
||||
return "login";
|
||||
@RequestMapping(value = "/check.query", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public Object check(HttpServletRequest request) {
|
||||
WebUtil.setSessionValue(request, WebUtil.NEED_LOGIN, configure.isLoginRequired());
|
||||
return new Boolean(configure.isLoginRequired());
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/check", method = RequestMethod.POST)
|
||||
@RequestMapping(value = "/login.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Object check(@RequestParam("username") String username,
|
||||
public Object login(@RequestParam("username") String username,
|
||||
@RequestParam(value = "password") String password,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) throws Exception {
|
||||
logger.info("user:{} login", username);
|
||||
User user = userService.queryByUsernameAndPassword(username, password);
|
||||
@@ -60,16 +65,19 @@ public class LoginController {
|
||||
if (user == null) {
|
||||
throw new IllegalArgumentException("Bad username or password!");
|
||||
} else {
|
||||
WebUtil.setCookie(response, WebUtil.LOGIN_TOKEN, cipherHelper.encrypt(username), false);
|
||||
WebUtil.setCookie(response, WebUtil.USER_NAME, username, false);
|
||||
user.setPassword(null);
|
||||
UserInfo userInfo = WebUtil.setLoginInfo(request, response, user);
|
||||
WebUtil.setSessionValue(request, WebUtil.USER_INFO, userInfo);
|
||||
WebUtil.setSessionValue(request, WebUtil.USER_NAME, username);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/logout", method = RequestMethod.POST)
|
||||
@RequestMapping(value = "/logout.do", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public void logout(HttpServletResponse response) {
|
||||
WebUtil.setCookie(response, WebUtil.LOGIN_TOKEN,"", true);
|
||||
WebUtil.setCookie(response, WebUtil.USER_NAME, "", true);
|
||||
public Object logout(HttpServletRequest request) {
|
||||
WebUtil.removeSession(request);
|
||||
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
|
@@ -17,11 +17,7 @@
|
||||
|
||||
package org.apache.rocketmq.console.interceptor;
|
||||
|
||||
import org.apache.rocketmq.console.model.UserInfo;
|
||||
import org.apache.rocketmq.console.service.LoginService;
|
||||
import org.apache.rocketmq.console.util.WebUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
@@ -31,8 +27,6 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class AuthInterceptor extends HandlerInterceptorAdapter {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private LoginService loginService;
|
||||
|
||||
@@ -43,14 +37,6 @@ public class AuthInterceptor extends HandlerInterceptorAdapter {
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UserInfo userInfo = loginService.parse(request, response);
|
||||
if (userInfo.getUser() == null) {
|
||||
logger.warn("cannot parse userinfo, userInfo:{}", userInfo);
|
||||
WebUtil.print(response, "User does not exist or wrong password");
|
||||
return false;
|
||||
}
|
||||
WebUtil.setAttribute(request, UserInfo.USER_INFO, userInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -35,6 +35,10 @@ public class User {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public User cloneOne() {
|
||||
return new User(this.name, this.password, this.type);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
@@ -17,13 +17,9 @@
|
||||
|
||||
package org.apache.rocketmq.console.service;
|
||||
|
||||
import org.apache.rocketmq.console.model.UserInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
public interface LoginService {
|
||||
String getLoginId(HttpServletRequest request);
|
||||
boolean login(HttpServletRequest request, HttpServletResponse response);
|
||||
UserInfo parse(HttpServletRequest request, HttpServletResponse response);
|
||||
}
|
||||
|
@@ -17,12 +17,9 @@
|
||||
|
||||
package org.apache.rocketmq.console.service.impl;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.console.config.RMQConfigure;
|
||||
import org.apache.rocketmq.console.model.UserInfo;
|
||||
import org.apache.rocketmq.console.service.LoginService;
|
||||
import org.apache.rocketmq.console.service.UserService;
|
||||
import org.apache.rocketmq.console.util.CipherHelper;
|
||||
import org.apache.rocketmq.console.util.WebUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -34,7 +31,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
@Service
|
||||
@@ -44,34 +40,13 @@ public class LoginServiceImpl implements LoginService {
|
||||
@Resource
|
||||
private RMQConfigure rmqConfigure;
|
||||
|
||||
@Resource
|
||||
private CipherHelper cipherHelper;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Override
|
||||
public String getLoginId(HttpServletRequest request) {
|
||||
String loginToken = WebUtil.getLoginCookieValue(request);
|
||||
if (loginToken != null) {
|
||||
String userName = cipherHelper.decrypt(loginToken);
|
||||
if (StringUtils.isNotBlank(loginToken)) {
|
||||
WebUtil.setAttribute(request, "username", userName);
|
||||
return userName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getLoginId(String ticket) {
|
||||
// You can extend this func to support external ticket
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean login(HttpServletRequest request, HttpServletResponse response) {
|
||||
String username = getLoginId(request);
|
||||
if (username != null) {
|
||||
if (WebUtil.getValueFromSession(request, WebUtil.USER_NAME) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -79,40 +54,6 @@ public class LoginServiceImpl implements LoginService {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo parse(HttpServletRequest request, HttpServletResponse response) {
|
||||
String ip = WebUtil.getIp(request);
|
||||
UserInfo userInfo = new UserInfo();
|
||||
userInfo.setIp(ip);
|
||||
userInfo.setLoginTime(System.currentTimeMillis());
|
||||
|
||||
Object username = WebUtil.getAttribute(request, "username");
|
||||
if (username == null) {
|
||||
userInfo.setUser(null);
|
||||
} else {
|
||||
userInfo.setUser(userService.queryByName(username.toString()));
|
||||
}
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
private String parseRedirect(HttpServletRequest request) throws Exception {
|
||||
try {
|
||||
String redirect = request.getParameter("redirect");
|
||||
String url = null;
|
||||
if (redirect != null) {
|
||||
url = URLDecoder.decode(redirect, "UTF-8");
|
||||
}
|
||||
if (url != null) {
|
||||
logger.info("redirect to:" + url);
|
||||
return url;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected void auth(HttpServletRequest request, HttpServletResponse response) {
|
||||
try {
|
||||
String url = WebUtil.getUrl(request);
|
||||
|
@@ -18,6 +18,7 @@
|
||||
package org.apache.rocketmq.console.service.impl;
|
||||
|
||||
import org.apache.rocketmq.console.config.RMQConfigure;
|
||||
import org.apache.rocketmq.console.exception.ServiceException;
|
||||
import org.apache.rocketmq.console.model.User;
|
||||
import org.apache.rocketmq.console.service.UserService;
|
||||
import org.apache.rocketmq.srvutil.FileWatchService;
|
||||
@@ -59,7 +60,7 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FileBasedUserInfoStore {
|
||||
/*packaged*/ static class FileBasedUserInfoStore {
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private static final String FILE_NAME = "users.properties";
|
||||
|
||||
@@ -68,9 +69,14 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
|
||||
|
||||
public FileBasedUserInfoStore(RMQConfigure configure) {
|
||||
log.info("XXXXXX " + configure);
|
||||
filePath = configure.getRocketMqConsoleDataPath() + File.separator + FILE_NAME;
|
||||
if (!new File(filePath).exists()) {
|
||||
//Use the default path
|
||||
filePath = this.getClass().getResource("/" + FILE_NAME).getPath();
|
||||
}
|
||||
log.info(String.format("Login Users configure file is %s", filePath));
|
||||
load();
|
||||
watch();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
@@ -79,7 +85,7 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
try {
|
||||
prop.load(new FileReader(filePath));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(String.format("Failed to load loginUserInfo property file: %s", filePath));
|
||||
throw new ServiceException(0, String.format("Failed to load loginUserInfo property file: %s", filePath));
|
||||
}
|
||||
|
||||
Map<String, User> loadUserMap = new HashMap<>();
|
||||
@@ -131,7 +137,7 @@ public class UserServiceImpl implements UserService, InitializingBean {
|
||||
public User queryByUsernameAndPassword(@NotNull String username, @NotNull String password) {
|
||||
User user = queryByName(username);
|
||||
if (user != null && password.equals(user.getPassword())) {
|
||||
return user;
|
||||
return user.cloneOne();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.console.util;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public class CipherHelper {
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private static final String ALGORITHM = "AES";
|
||||
|
||||
private SecretKeySpec secretKeySpec;
|
||||
|
||||
public CipherHelper(String ciperKey) throws UnsupportedEncodingException {
|
||||
secretKeySpec = new SecretKeySpec(ciperKey.getBytes("UTF-8"), ALGORITHM);
|
||||
}
|
||||
|
||||
/**
|
||||
* encrypt
|
||||
* @param toBeEncrypt
|
||||
* @return
|
||||
*/
|
||||
public String encrypt(String toBeEncrypt) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||
byte[] encrypted = cipher.doFinal(toBeEncrypt.getBytes());
|
||||
return Base64.encodeBase64String(encrypted);
|
||||
} catch (Exception e) {
|
||||
logger.error("encrypt:{} err", toBeEncrypt, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* decrypt
|
||||
* @param encrypted
|
||||
* @return
|
||||
*/
|
||||
public String decrypt(String encrypted) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance(ALGORITHM);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||
byte[] decryptedBytes = cipher.doFinal(Base64.decodeBase64(encrypted));
|
||||
return new String(decryptedBytes);
|
||||
} catch (Exception e) {
|
||||
logger.error("decrypt:{} err", encrypted, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -18,17 +18,20 @@
|
||||
package org.apache.rocketmq.console.util;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.rocketmq.console.model.User;
|
||||
import org.apache.rocketmq.console.model.UserInfo;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class WebUtil {
|
||||
public static final String LOGIN_TOKEN = "TOKEN";
|
||||
public static final String USER_INFO = "userInfo";
|
||||
public static final String USER_NAME = "username";
|
||||
public static final String NEED_LOGIN = "needLogin";
|
||||
|
||||
/**
|
||||
* Obtain ServletRequest header value
|
||||
@@ -66,48 +69,6 @@ public class WebUtil {
|
||||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain cookie
|
||||
*
|
||||
* @param request
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public static Cookie getCookie(HttpServletRequest request, String name) {
|
||||
Cookie[] cookies = request.getCookies();
|
||||
if (cookies != null) {
|
||||
for (Cookie cookie : cookies) {
|
||||
if (name.equals(cookie.getName())) {
|
||||
return cookie;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void setCookie(HttpServletResponse response, String key, String value, boolean removeFlag) {
|
||||
Cookie cookie = new Cookie(key, value);
|
||||
cookie.setPath("/");
|
||||
if (removeFlag) {
|
||||
cookie.setMaxAge(0);
|
||||
}
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain login cookie info
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static String getLoginCookieValue(HttpServletRequest request) {
|
||||
Cookie cookie = getCookie(request, LOGIN_TOKEN);
|
||||
if (cookie != null) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void redirect(HttpServletResponse response, HttpServletRequest request, String path) throws IOException {
|
||||
response.sendRedirect(request.getContextPath() + path);
|
||||
}
|
||||
@@ -127,26 +88,6 @@ public class WebUtil {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch attribute form request
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static void setAttribute(ServletRequest request, String name, Object obj) {
|
||||
request.setAttribute(name, obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set attribute to request
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static Object getAttribute(ServletRequest request, String name) {
|
||||
return request.getAttribute(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write content to front-page/response
|
||||
*
|
||||
@@ -161,4 +102,35 @@ public class WebUtil {
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static Object getValueFromSession(HttpServletRequest request, String key) {
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
if (session != null) {
|
||||
return session.getAttribute(key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static UserInfo setLoginInfo(HttpServletRequest request, HttpServletResponse response, User user) {
|
||||
String ip = WebUtil.getIp(request);
|
||||
UserInfo userInfo = new UserInfo();
|
||||
userInfo.setIp(ip);
|
||||
userInfo.setLoginTime(System.currentTimeMillis());
|
||||
|
||||
userInfo.setUser(user);
|
||||
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
public static void removeSession(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession();
|
||||
session.invalidate();
|
||||
}
|
||||
|
||||
public static void setSessionValue(HttpServletRequest request, String key, Object value) {
|
||||
HttpSession session = request.getSession();
|
||||
session.setAttribute(key, value);
|
||||
}
|
||||
}
|
||||
|
@@ -26,4 +26,4 @@ rocketmq.config.msgTrackTopicName=
|
||||
rocketmq.config.ticketKey=ticket
|
||||
|
||||
#Must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
rocketmq.config.loginRequired=true
|
||||
rocketmq.config.loginRequired=false
|
@@ -15,6 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
'use strict';
|
||||
var initFlag = false;
|
||||
var loginFlag = false;
|
||||
var app = angular.module('app', [
|
||||
'ngAnimate',
|
||||
'ngCookies',
|
||||
@@ -29,43 +31,60 @@ var app = angular.module('app', [
|
||||
'localytics.directives',
|
||||
'pascalprecht.translate'
|
||||
]).run(
|
||||
['$rootScope','$location','$cookies','$http',
|
||||
function ($rootScope,$location,$cookies,$http) {
|
||||
// var filter = function(url){
|
||||
// var outFilterArrs = []
|
||||
// outFilterArrs.push("/login");
|
||||
// outFilterArrs.push("/reg");
|
||||
// outFilterArrs.push("/logout");
|
||||
// outFilterArrs.push("/404");
|
||||
// var flag = false;
|
||||
// $.each(outFilterArrs,function(i,value){
|
||||
// if(url.indexOf(value) > -1){
|
||||
// flag = true;
|
||||
// return false;
|
||||
// }
|
||||
// });
|
||||
// return flag;
|
||||
// }
|
||||
['$rootScope','$location','$cookies','$http', '$window','Notification',
|
||||
function ($rootScope,$location,$cookies,$http, $window, Notification) {
|
||||
var init = function(callback){
|
||||
if (initFlag) return;
|
||||
initFlag = true;
|
||||
|
||||
// if(angular.isDefined($cookies.get("isLogin")) && $cookies.get("isLogin") == 'true'){
|
||||
// chatApi.login();
|
||||
// }
|
||||
//TODO: make the session timeout consistent with backend
|
||||
// var sessionId = $cookies.get("JSESSIONID");
|
||||
// console.log("sessionId "+ sessionId);
|
||||
//
|
||||
// if (sessionId === undefined || sessionId == null) {
|
||||
// $window.sessionStorage.clear();
|
||||
// }
|
||||
|
||||
$rootScope.username = $cookies.get("username");
|
||||
if (!angular.isDefined($rootScope.username)) {
|
||||
$rootScope.username = '';
|
||||
var url = '/login/check.query';
|
||||
var setting = {
|
||||
type: "GET",
|
||||
timeout:15000,
|
||||
success:callback,
|
||||
async:false
|
||||
}
|
||||
//sync invoke
|
||||
$.ajax(url,setting)
|
||||
}
|
||||
console.log("username " + $rootScope.username);
|
||||
$rootScope.globals = $cookies.get('TOKEN');
|
||||
console.log('TOKEN ' + $rootScope.globals);
|
||||
console.log('initFlag0='+ initFlag + ' loginFlag0==='+loginFlag);
|
||||
|
||||
$rootScope.$on('$locationChangeStart', function (event, next, current) {
|
||||
// redirect to login page if not logged in and trying to access a restricted page
|
||||
var restrictedPage = $.inArray($location.path(), ['/login']) === -1;
|
||||
var loggedIn = $rootScope.globals;
|
||||
if (restrictedPage && (!angular.isDefined(loggedIn) || !loggedIn)) {
|
||||
var callback = $location.path();
|
||||
$location.path('/login');
|
||||
init(function(resp){
|
||||
if (resp.status == 0) {
|
||||
// console.log('resp.data==='+resp.data);
|
||||
loginFlag = resp.data;
|
||||
}else {
|
||||
Notification.error({message: "" + resp.errMsg, delay: 2000});
|
||||
}
|
||||
});
|
||||
|
||||
console.log('initFlag='+ initFlag + ' loginFlag==='+loginFlag);
|
||||
$rootScope.username = '';
|
||||
if (loginFlag || loginFlag == "true") {
|
||||
var username = $window.sessionStorage.getItem("username");
|
||||
|
||||
if (username != null) {
|
||||
$rootScope.username = username;
|
||||
}
|
||||
|
||||
// console.log("username " + $rootScope.username);
|
||||
var restrictedPage = $.inArray($location.path(), ['/login']) === -1;
|
||||
if (restrictedPage && !username) {
|
||||
var callback = $location.path();
|
||||
$location.path('/login');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -94,6 +113,19 @@ var app = angular.module('app', [
|
||||
}
|
||||
});
|
||||
|
||||
app.factory('abc', function ($http, $window) {
|
||||
console.log('xxxxxxx');
|
||||
$http({
|
||||
method: "GET",
|
||||
url: "/login/check.query"
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
alert(resp.data)
|
||||
}
|
||||
});
|
||||
return 1;
|
||||
});
|
||||
|
||||
app.provider('getDictName', function () {
|
||||
|
||||
var dictList = [];
|
||||
@@ -142,6 +174,9 @@ app.config(['$routeProvider', '$httpProvider','$cookiesProvider','getDictNamePro
|
||||
}
|
||||
});
|
||||
|
||||
// check login status
|
||||
|
||||
|
||||
$httpProvider.defaults.cache = false;
|
||||
|
||||
$routeProvider.when('/', {
|
||||
|
@@ -14,7 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
app.controller('AppCtrl', ['$scope','$rootScope','$cookies','$location','$translate','$http','Notification', function ($scope,$rootScope,$cookies,$location,$translate, $http, Notification) {
|
||||
app.controller('AppCtrl', ['$scope','$window','$translate','$http','Notification', function ($scope,$window,$translate, $http, Notification) {
|
||||
$scope.changeTranslate = function(langKey){
|
||||
$translate.use(langKey);
|
||||
}
|
||||
@@ -22,10 +22,10 @@ app.controller('AppCtrl', ['$scope','$rootScope','$cookies','$location','$transl
|
||||
$scope.logout = function(){
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "login/logout"
|
||||
url: "login/logout.do"
|
||||
}).success(function (resp) {
|
||||
window.location = "/";
|
||||
$cookies.remove("username");
|
||||
$window.sessionStorage.clear();
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
app.controller('loginController', ['$scope','$location','$http','Notification','$cookies', function ($scope,$location,$http,Notification,$cookies) {
|
||||
app.controller('loginController', ['$scope','$location','$http','Notification','$cookies','$window', function ($scope,$location,$http,Notification,$cookies, $window) {
|
||||
$scope.login = function () {
|
||||
if(!$("#username").val()) {
|
||||
alert("用户名不能为空");
|
||||
@@ -28,12 +28,14 @@ app.controller('loginController', ['$scope','$location','$http','Notification','
|
||||
|
||||
$http({
|
||||
method: "POST",
|
||||
url: "login/check",
|
||||
url: "login/login.do",
|
||||
params:{username:$("#username").val(), password:$("#password").val()}
|
||||
}).success(function (resp) {
|
||||
if (resp.status == 0) {
|
||||
Notification.info({message: 'Login successful, redirect now', delay: 2000});
|
||||
$window.sessionStorage.setItem("username", $("#username").val());
|
||||
window.location = "/";
|
||||
initFlag = false;
|
||||
} else{
|
||||
Notification.error({message: resp.errMsg, delay: 2000});
|
||||
}
|
||||
|
@@ -37,8 +37,6 @@
|
||||
</div>
|
||||
<script>
|
||||
$(function(){
|
||||
console.log('aaaaa111');
|
||||
//$("#loginModal").modal("hide");
|
||||
console.log('aaaaa');
|
||||
})
|
||||
</script>
|
9
src/main/resources/users.properties
Normal file
9
src/main/resources/users.properties
Normal file
@@ -0,0 +1,9 @@
|
||||
# This file supports hot change, any change will be auto-reloaded without Console restarting.
|
||||
# Format: a user per line, username=password[,N] #N is optional, 0 (Normal User); 1 (Admin)
|
||||
|
||||
# Define Admin
|
||||
admin=admin,1
|
||||
|
||||
# Define Users
|
||||
user1=user1
|
||||
user2=user2
|
@@ -0,0 +1,26 @@
|
||||
package org.apache.rocketmq.console.service.impl;
|
||||
|
||||
import org.apache.rocketmq.console.config.RMQConfigure;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class LoginFileTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad() throws Exception {
|
||||
RMQConfigure configure = new RMQConfigure();
|
||||
configure.setDataPath(this.getClass().getResource("/").getPath());
|
||||
|
||||
UserServiceImpl.FileBasedUserInfoStore fileBasedUserInfoStore = new UserServiceImpl.FileBasedUserInfoStore(configure);
|
||||
Assert.assertTrue("No exception raise for FileBasedUserInfoStore", true);
|
||||
}
|
||||
}
|
2
src/test/resources/users.properties
Normal file
2
src/test/resources/users.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
admin=admin
|
||||
test=test
|
Reference in New Issue
Block a user