diff --git a/.gitignore b/.gitignore
index 3d31f5c62e..7647865be8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,7 +27,7 @@ target/
.DS_Store
node_modules
/dist
-
+node/
# local env files
.env.demo
@@ -47,5 +47,10 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
+*.lock
+*.classpath
+*.project
+.settings/
+
package-lock.json
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000..da05358bd4
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM registry.fit2cloud.com/fit2cloud3/fabric8-java-alpine-openjdk8-jre
+
+ARG IMAGE_TAG
+
+RUN mkdir -p /opt/apps
+
+ADD backend/target/backend-1.0.jar /opt/apps
+
+ENV JAVA_APP_JAR=/opt/apps/backend-1.0.jar
+
+ENV AB_OFF=true
+
+ENV JAVA_OPTIONS=-Dfile.encoding=utf-8
+
+HEALTHCHECK --interval=15s --timeout=5s --retries=20 --start-period=30s CMD curl -f 127.0.0.1:8081
+
+CMD ["/deployments/run-java.sh"]
diff --git a/backend/pom.xml b/backend/pom.xml
index c814656394..80a883c497 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -303,17 +303,6 @@
reflections8
0.11.7
-
-
org.springframework.boot
@@ -325,6 +314,25 @@
ehcache
2.9.1
+
+
+ org.apache.hbase
+ hbase-client
+ 2.4.1
+
+
+ org.apache.hbase
+ hbase-common
+ 2.4.1
+
+
+
+ org.testng
+ testng
+ 6.8
+ test
+
+
@@ -430,6 +438,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
index 4dee2a8df7..5d686c2abe 100644
--- a/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
+++ b/backend/src/main/java/io/dataease/auth/config/F2CRealm.java
@@ -13,8 +13,9 @@ import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
-import javax.annotation.Resource;
import java.util.Set;
import java.util.stream.Collectors;
@@ -23,7 +24,8 @@ import java.util.stream.Collectors;
@Component
public class F2CRealm extends AuthorizingRealm {
- @Resource
+ @Autowired
+ @Lazy //shiro组件加载过早 让authUserService等一等再注入 否则 注入的可能不是代理对象
private AuthUserService authUserService;
@@ -36,7 +38,6 @@ public class F2CRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
Long userId = JWTUtils.tokenInfoByToken(principals.toString()).getUserId();
- //SysUserEntity user = authUserService.getUserById(userId);
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
Set role = authUserService.roles(userId).stream().collect(Collectors.toSet());
simpleAuthorizationInfo.addRoles(role);
diff --git a/backend/src/main/java/io/dataease/auth/config/WhitelistConfig.java b/backend/src/main/java/io/dataease/auth/config/WhitelistConfig.java
new file mode 100644
index 0000000000..357222cc20
--- /dev/null
+++ b/backend/src/main/java/io/dataease/auth/config/WhitelistConfig.java
@@ -0,0 +1,17 @@
+package io.dataease.auth.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+@Configuration
+@ConfigurationProperties(prefix = "dataease")
+@Data
+public class WhitelistConfig {
+
+ private List whitelist;
+
+
+}
diff --git a/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java b/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
index 7a0602d105..314803d371 100644
--- a/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
+++ b/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java
@@ -6,6 +6,9 @@ import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.service.AuthUserService;
import io.dataease.auth.util.JWTUtils;
import io.dataease.commons.utils.CommonBeanFactory;
+import io.dataease.commons.utils.ServletUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
@@ -23,6 +26,8 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());
+ public final static String expireMessage = "login token is expire";
+
/*@Autowired
private AuthUserService authUserService;*/
@@ -45,7 +50,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
-
+ // 当没有出现登录超时 且需要刷新token 则执行刷新token
+ if (JWTUtils.loginExpire(authorization)){
+ throw new AuthenticationException(expireMessage);
+ }
if (JWTUtils.needRefresh(authorization)){
authorization = refreshToken(request, response);
}
@@ -67,7 +75,12 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
boolean loginSuccess = executeLogin(request, response);
return loginSuccess;
} catch (Exception e) {
- response401(request, response);
+ if (e instanceof AuthenticationException && StringUtils.equals(e.getMessage(), expireMessage)){
+ responseExpire(request, response);
+ }else {
+ response401(request, response);
+ }
+
}
}
return false;
@@ -81,7 +94,13 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class);
SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId());
String password = user.getPassword();
+
+ // 删除老token操作时间
+ JWTUtils.removeTokenExpire(token);
String newToken = JWTUtils.sign(tokenInfo, password);
+ // 记录新token操作时间
+ JWTUtils.addTokenExpire(newToken);
+
JWTToken jwtToken = new JWTToken(newToken);
this.getSubject(request, response).login(jwtToken);
// 设置响应的Header头新Token
@@ -123,4 +142,16 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
LOGGER.error(e.getMessage());
}
}
+
+ private void responseExpire(ServletRequest req, ServletResponse resp) {
+ try {
+ HttpServletResponse httpServletResponse = (HttpServletResponse) resp;
+ httpServletResponse.addHeader("Access-Control-Expose-Headers", "authentication-status");
+ httpServletResponse.setHeader("authentication-status", "login_expire");
+ httpServletResponse.setStatus(401);
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
+ }
+
}
diff --git a/backend/src/main/java/io/dataease/auth/server/AuthServer.java b/backend/src/main/java/io/dataease/auth/server/AuthServer.java
index bdb56b337b..474e013a69 100644
--- a/backend/src/main/java/io/dataease/auth/server/AuthServer.java
+++ b/backend/src/main/java/io/dataease/auth/server/AuthServer.java
@@ -49,6 +49,8 @@ public class AuthServer implements AuthApi {
Map result = new HashMap<>();
TokenInfo tokenInfo = TokenInfo.builder().userId(user.getUserId()).username(username).lastLoginTime(System.currentTimeMillis()).build();
String token = JWTUtils.sign(tokenInfo, realPwd);
+ // 记录token操作时间
+ JWTUtils.addTokenExpire(token);
result.put("token", token);
ServletUtils.setToken(token);
return result;
@@ -79,6 +81,9 @@ public class AuthServer implements AuthApi {
@Override
public String test() {
+ SysUserEntity userById = authUserService.getUserById(4L);
+ String nickName = userById.getNickName();
+ System.out.println(nickName);
return "apple";
}
}
diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
index f8ffd69827..53894c4e8d 100644
--- a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
+++ b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
@@ -1,17 +1,22 @@
package io.dataease.auth.service.impl;
+import io.dataease.auth.config.WhitelistConfig;
import io.dataease.auth.service.ShiroService;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.StringJoiner;
@Service
public class ShiroServiceImpl implements ShiroService {
+
+ private final static String ANON = "anon";
+
+ @Autowired
+ private WhitelistConfig whitelistConfig;
@Override
public Map loadFilterChainDefinitionMap() {
@@ -20,47 +25,38 @@ public class ShiroServiceImpl implements ShiroService {
// 配置过滤:不会被拦截的链接 -> 放行 start ----------------------------------------------------------
// 放行Swagger2页面,需要放行这些
- filterChainDefinitionMap.put("/swagger-ui.html","anon");
- filterChainDefinitionMap.put("/swagger-ui/**","anon");
-
- filterChainDefinitionMap.put("/swagger/**","anon");
- filterChainDefinitionMap.put("/webjars/**", "anon");
- filterChainDefinitionMap.put("/swagger-resources/**","anon");
- filterChainDefinitionMap.put("/v2/**","anon");
- filterChainDefinitionMap.put("/v3/**","anon");
- filterChainDefinitionMap.put("/static/**", "anon");
- filterChainDefinitionMap.put("/common-files/**", "anon");
-
-
- // filterChainDefinitionMap.put("/401", "anon");
- // filterChainDefinitionMap.put("/404", "anon");
- // 登陆
- // filterChainDefinitionMap.put("/api/auth/logout", "anon");
- filterChainDefinitionMap.put("/api/auth/login", "anon");
- // 退出
-
- // 放行未授权接口,重定向使用
- filterChainDefinitionMap.put("/unauth", "anon");
- filterChainDefinitionMap.put("/display/**", "anon");
-
- // token过期接口
- filterChainDefinitionMap.put("/tokenExpired", "anon");
- // 被挤下线
- filterChainDefinitionMap.put("/downline", "anon");
- // 放行 end ----------------------------------------------------------
-
- /*List extPermissionBeans = extUserMapper.getPermissions();
-
- extPermissionBeans.forEach(item -> {
- StringJoiner f2cPerms = new StringJoiner(",", "f2cPerms[", "]");
- f2cPerms.add(item.getPermission());
- filterChainDefinitionMap.put(item.getPath(), "jwt," + f2cPerms);
+ filterChainDefinitionMap.put("/swagger-ui.html",ANON);
+ filterChainDefinitionMap.put("/swagger-ui/**",ANON);
+ filterChainDefinitionMap.put("/swagger/**",ANON);
+ filterChainDefinitionMap.put("/webjars/**", ANON);
+ filterChainDefinitionMap.put("/swagger-resources/**",ANON);
+ filterChainDefinitionMap.put("/v2/**",ANON);
+ filterChainDefinitionMap.put("/v3/**",ANON);
+ filterChainDefinitionMap.put("/static/**", ANON);
+ filterChainDefinitionMap.put("/css/**", ANON);
+ filterChainDefinitionMap.put("/js/**", ANON);
+ filterChainDefinitionMap.put("/img/**", ANON);
+ filterChainDefinitionMap.put("/fonts/**", ANON);
+ filterChainDefinitionMap.put("/favicon.ico", ANON);
+ filterChainDefinitionMap.put("/", ANON);
+ filterChainDefinitionMap.put("/index.html", ANON);
+ filterChainDefinitionMap.put("/api/auth/login", ANON);
+ filterChainDefinitionMap.put("/unauth", ANON);
+ filterChainDefinitionMap.put("/display/**", ANON);
+ filterChainDefinitionMap.put("/tokenExpired", ANON);
+ filterChainDefinitionMap.put("/downline", ANON);
+ List whitelist = whitelistConfig.getWhitelist();
+ if (CollectionUtils.isNotEmpty(whitelist))
+ whitelist.forEach(path -> {
+ filterChainDefinitionMap.put(path, ANON);
});
-*/
+
filterChainDefinitionMap.put("/api/auth/logout", "logout");
filterChainDefinitionMap.put("/**", "jwt");
return filterChainDefinitionMap;
}
+
+
@Override
public void updatePermission(ShiroFilterFactoryBean shiroFilterFactoryBean, Integer roleId, Boolean isRemoveSession) {
diff --git a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
index 32b20022a7..b43ae98bd3 100644
--- a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
+++ b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java
@@ -6,20 +6,23 @@ import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import io.dataease.auth.entity.TokenInfo;
-import io.dataease.commons.utils.ServletUtils;
+import io.dataease.auth.filter.JWTFilter;
+import io.dataease.commons.utils.CommonBeanFactory;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
-import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.authc.AuthenticationException;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
import java.util.Date;
public class JWTUtils {
- // token过期时间5min (过期会自动刷新续命 目的是避免一直都是同一个token )
- private static final long EXPIRE_TIME = 1*60*1000;
+ // token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token )
+ private static final long EXPIRE_TIME = 1*60*1000/2;
// 登录间隔时间10min 超过这个时间强制重新登录
- private static final long Login_Interval = 10*60*1000;
+ private static final long Login_Interval = 20*60*1000;
/**
@@ -35,16 +38,12 @@ public class JWTUtils {
.withClaim("username", tokenInfo.getUsername())
.withClaim("userId", tokenInfo.getUserId())
.build();
- DecodedJWT jwt = verifier.verify(token);
- Long lastLoginTime = jwt.getClaim("lastLoginTime").asLong();
- long now = System.currentTimeMillis();
- if (now - lastLoginTime > Login_Interval){
+ verifier.verify(token);
+ if (loginExpire(token)){
// 登录超时
- HttpServletResponse response = ServletUtils.response();
- response.addHeader("Access-Control-Expose-Headers", "authentication-status");
- response.setHeader("authentication-status", "login_expire");
+ throw new AuthenticationException(JWTFilter.expireMessage);
// 前端拦截 登录超时状态 直接logout
- return false;
+ //return false;
}
return true;
}
@@ -74,6 +73,17 @@ public class JWTUtils {
return new Date().getTime() >= exp.getTime();
}
+ /**
+ * 当前token是否登录超时
+ * @param token
+ * @return
+ */
+ public static boolean loginExpire(String token){
+ Long now = System.currentTimeMillis();
+ Long lastOperateTime = tokenLastOperateTime(token);
+ return now - lastOperateTime > Login_Interval;
+ }
+
public static Date getExp(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
@@ -106,4 +116,29 @@ public class JWTUtils {
return null;
}
}
+
+ /**
+ * 获取当前token上次操作时间
+ * @param token
+ * @return
+ */
+ public static Long tokenLastOperateTime(String token){
+ CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
+ Cache tokens_expire = cacheManager.getCache("tokens_expire");
+ Long expTime = tokens_expire.get(token, Long.class);
+ return expTime;
+ }
+
+ public static void removeTokenExpire(String token){
+ CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
+ Cache tokens_expire = cacheManager.getCache("tokens_expire");
+ tokens_expire.evict(token);
+ }
+
+ public static void addTokenExpire(String token){
+ CacheManager cacheManager = CommonBeanFactory.getBean(CacheManager.class);
+ Cache tokens_expire = cacheManager.getCache("tokens_expire");
+ long now = System.currentTimeMillis();
+ tokens_expire.put(token, now);
+ }
}
diff --git a/backend/src/main/java/io/dataease/base/domain/DatasetTableField.java b/backend/src/main/java/io/dataease/base/domain/DatasetTableField.java
index 6e7288c65e..9cd293962b 100644
--- a/backend/src/main/java/io/dataease/base/domain/DatasetTableField.java
+++ b/backend/src/main/java/io/dataease/base/domain/DatasetTableField.java
@@ -1,9 +1,12 @@
package io.dataease.base.domain;
import java.io.Serializable;
+
+import lombok.Builder;
import lombok.Data;
@Data
+@Builder
public class DatasetTableField implements Serializable {
private String id;
@@ -24,4 +27,4 @@ public class DatasetTableField implements Serializable {
private Integer deType;
private static final long serialVersionUID = 1L;
-}
\ No newline at end of file
+}
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.java b/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.java
index f8f8b503ad..5a71f86c61 100644
--- a/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.java
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.java
@@ -1,9 +1,8 @@
package io.dataease.base.mapper.ext;
-import org.apache.ibatis.annotations.Delete;
-import org.apache.ibatis.annotations.Mapper;
-import org.apache.ibatis.annotations.Param;
-import org.apache.ibatis.annotations.Update;
+import io.dataease.base.mapper.ext.query.GridExample;
+import io.dataease.controller.sys.request.SimpleTreeNode;
+import org.apache.ibatis.annotations.*;
import java.util.List;
@@ -22,4 +21,9 @@ public interface ExtDeptMapper {
" #{id} " +
"")
int batchDelete(@Param("ids") List ids);
+
+
+ List allNodes();
+
+ List nodesByExample(GridExample example);
}
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.xml b/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.xml
new file mode 100644
index 0000000000..9dcec17d12
--- /dev/null
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtDeptMapper.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.java b/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.java
index 31ae070772..05c47bff5d 100644
--- a/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.java
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.java
@@ -1,6 +1,7 @@
package io.dataease.base.mapper.ext;
import io.dataease.base.domain.SysRole;
+import io.dataease.base.mapper.ext.query.GridExample;
import io.dataease.controller.sys.request.RoleGridRequest;
import io.dataease.controller.sys.response.RoleUserItem;
import org.apache.ibatis.annotations.Param;
@@ -12,7 +13,7 @@ import java.util.Map;
public interface ExtSysRoleMapper {
- List query(@Param("request")RoleGridRequest request);
+ List query(GridExample example);
int deleteRoleMenu(@Param("roleId") Long roleId);
diff --git a/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.xml b/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.xml
index 37459e831b..1f3fe93d21 100644
--- a/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.xml
+++ b/backend/src/main/java/io/dataease/base/mapper/ext/ExtSysRoleMapper.xml
@@ -9,15 +9,19 @@
-