diff --git a/backend/src/main/java/io/dataease/auth/filter/F2CDocFilter.java b/backend/src/main/java/io/dataease/auth/filter/F2CDocFilter.java index d5d8438c3a..ef1c304810 100644 --- a/backend/src/main/java/io/dataease/auth/filter/F2CDocFilter.java +++ b/backend/src/main/java/io/dataease/auth/filter/F2CDocFilter.java @@ -79,12 +79,7 @@ public class F2CDocFilter extends AccessControlFilter { if (StringUtils.isBlank(authorization)) { return false; } - if (JWTUtils.loginExpire(authorization)) { - return false; - } - if (JWTUtils.needRefresh(authorization)) { - authorization = refreshToken(authorization); - } + TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(authorization); AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class); SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId()); @@ -96,20 +91,6 @@ public class F2CDocFilter extends AccessControlFilter { return verify; } - private String refreshToken(String token) throws Exception { - TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token); - AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class); - SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId()); - if (user == null) { - DataEaseException.throwException(Translator.get("i18n_not_find_user")); - } - String password = user.getPassword(); - Algorithm algorithm = Algorithm.HMAC256(password); - JWTUtils.verifySign(algorithm, token); - String newToken = JWTUtils.sign(tokenInfo, password); - return newToken; - } - @Override protected boolean onAccessDenied(ServletRequest req, ServletResponse res) throws Exception { HttpServletResponse response = (HttpServletResponse) res; 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 0d70181289..83c73fc1ca 100644 --- a/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java +++ b/backend/src/main/java/io/dataease/auth/filter/JWTFilter.java @@ -1,24 +1,18 @@ package io.dataease.auth.filter; -import com.auth0.jwt.algorithms.Algorithm; import io.dataease.auth.entity.ASKToken; import io.dataease.auth.entity.JWTToken; -import io.dataease.auth.entity.SysUserEntity; -import io.dataease.auth.entity.TokenInfo; + import io.dataease.auth.handler.ApiKeyHandler; -import io.dataease.auth.service.AuthUserService; -import io.dataease.auth.util.JWTUtils; -import io.dataease.commons.utils.CommonBeanFactory; + import io.dataease.commons.utils.LogUtil; import io.dataease.commons.utils.TokenCacheUtils; -import io.dataease.exception.DataEaseException; -import io.dataease.i18n.Translator; + 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; -import org.slf4j.LoggerFactory; + import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestMethod; @@ -30,7 +24,6 @@ import javax.servlet.http.HttpServletResponse; public class JWTFilter extends BasicHttpAuthenticationFilter { - private Logger LOGGER = LoggerFactory.getLogger(this.getClass()); public final static String expireMessage = "Login token is expire."; @@ -69,14 +62,7 @@ public class JWTFilter extends BasicHttpAuthenticationFilter { if (TokenCacheUtils.invalid(authorization)) { throw new AuthenticationException(expireMessage); } - // 当没有出现登录超时 且需要刷新token 则执行刷新token - if (JWTUtils.loginExpire(authorization)) { - TokenCacheUtils.remove(authorization); - throw new AuthenticationException(expireMessage); - } - if (JWTUtils.needRefresh(authorization)) { - authorization = refreshToken(request, response); - } + JWTToken token = new JWTToken(authorization); Subject subject = getSubject(request, response); // 提交给realm进行登入,如果错误他会抛出异常并被捕获 @@ -110,28 +96,6 @@ public class JWTFilter extends BasicHttpAuthenticationFilter { } - private String refreshToken(ServletRequest request, ServletResponse response) throws Exception { - // 获取AccessToken(Shiro中getAuthzHeader方法已经实现) - String token = this.getAuthzHeader(request); - // 获取当前Token的帐号信息 - TokenInfo tokenInfo = JWTUtils.tokenInfoByToken(token); - AuthUserService authUserService = CommonBeanFactory.getBean(AuthUserService.class); - SysUserEntity user = authUserService.getUserById(tokenInfo.getUserId()); - if (user == null) { - DataEaseException.throwException(Translator.get("i18n_not_find_user")); - } - String password = user.getPassword(); - Algorithm algorithm = Algorithm.HMAC256(password); - JWTUtils.verifySign(algorithm, token); - String newToken = JWTUtils.sign(tokenInfo, password); - // 设置响应的Header头新Token - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - httpServletResponse.addHeader("Access-Control-Expose-Headers", "RefreshAuthorization"); - httpServletResponse.setHeader("RefreshAuthorization", newToken); - return newToken; - } - - /** * 对跨域提供支持 */ 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 fc297d1e17..a541433842 100644 --- a/backend/src/main/java/io/dataease/auth/util/JWTUtils.java +++ b/backend/src/main/java/io/dataease/auth/util/JWTUtils.java @@ -4,7 +4,6 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTCreator.Builder; import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; import io.dataease.auth.entity.TokenInfo; @@ -19,10 +18,8 @@ import java.util.Date; public class JWTUtils { - // token过期时间1min (过期会自动刷新续命 目的是避免一直都是同一个token ) - private static final long EXPIRE_TIME = 1 * 60 * 1000; - // 登录间隔时间10min 超过这个时间强制重新登录 - private static long Login_Interval; + + private static Long expireTime; /** * 校验token是否正确 @@ -65,62 +62,24 @@ public class JWTUtils { return tokenInfoBuilder.build(); } - public static boolean needRefresh(String token) { - Date exp = JWTUtils.getExp(token); - Long advanceTime = 5000L; - return (new Date().getTime() + advanceTime) >= exp.getTime(); - } - /** - * 当前token是否登录超时 - * - * @param token - * @return - */ - public static boolean loginExpire(String token) { - if (Login_Interval == 0) { - // 默认超时时间是8h - Long minute = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, - 8 * 60L); - // 分钟换算成毫秒 - Login_Interval = minute * 1000 * 60; - } - Long lastOperateTime = tokenLastOperateTime(token); - boolean isExpire = true; - if (lastOperateTime != null) { - Long now = System.currentTimeMillis(); - isExpire = now - lastOperateTime > Login_Interval; - } - return isExpire; - } - - public static Date getExp(String token) { - try { - DecodedJWT jwt = JWT.decode(token); - return jwt.getClaim("exp").asDate(); - } catch (JWTDecodeException e) { - e.printStackTrace(); - return null; - } - } - - /** - * 生成签名,5min后过期 - * * @param tokenInfo 用户信息 * @param secret 用户的密码 * @return 加密的token */ public static String sign(TokenInfo tokenInfo, String secret) { try { - Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); + if (ObjectUtils.isEmpty(expireTime)) { + expireTime = CommonBeanFactory.getBean(Environment.class).getProperty("dataease.login_timeout", Long.class, 480L); + } + long expireTimeMillis = expireTime * 60000L; + Date date = new Date(System.currentTimeMillis() + expireTimeMillis); Algorithm algorithm = Algorithm.HMAC256(secret); Builder builder = JWT.create() .withClaim("username", tokenInfo.getUsername()) .withClaim("userId", tokenInfo.getUserId()); String sign = builder.withExpiresAt(date).sign(algorithm); return sign; - } catch (Exception e) { return null; } @@ -143,7 +102,6 @@ public class JWTUtils { } else { verifier = JWT.require(algorithm).withClaim("resourceId", resourceId).withClaim("userId", userId).build(); } - try { verifier.verify(token); return true; @@ -152,16 +110,5 @@ public class JWTUtils { } } - /** - * 获取当前token上次操作时间 - * - * @param token - * @return - */ - public static Long tokenLastOperateTime(String token) { - DecodedJWT jwt = JWT.decode(token); - Date expiresAt = jwt.getExpiresAt(); - return expiresAt.getTime(); - } } diff --git a/backend/src/main/java/io/dataease/commons/utils/TokenCacheUtils.java b/backend/src/main/java/io/dataease/commons/utils/TokenCacheUtils.java index 0bcec3b8c8..32b68267ab 100644 --- a/backend/src/main/java/io/dataease/commons/utils/TokenCacheUtils.java +++ b/backend/src/main/java/io/dataease/commons/utils/TokenCacheUtils.java @@ -50,8 +50,9 @@ public class TokenCacheUtils { } Long time = expTime * 60; - CacheUtils.put(KEY, token, userId, time.intValue(), null); - + Double v = time * 0.6; + CacheUtils.put(KEY, token, userId, time.intValue(), v.intValue()); + CacheUtils.flush(KEY); } public static void remove(String token) { diff --git a/backend/src/main/java/io/dataease/listener/ApplicationCloseEventListener.java b/backend/src/main/java/io/dataease/listener/ApplicationCloseEventListener.java new file mode 100644 index 0000000000..4fde79311f --- /dev/null +++ b/backend/src/main/java/io/dataease/listener/ApplicationCloseEventListener.java @@ -0,0 +1,24 @@ +package io.dataease.listener; + +import io.dataease.commons.utils.LogUtil; +import net.sf.ehcache.CacheManager; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.stereotype.Component; + +@Component +public class ApplicationCloseEventListener implements ApplicationListener { + + @Autowired(required = false) + CacheManager cacheManager; + + @Override + public void onApplicationEvent(ContextClosedEvent event) { + + if (ObjectUtils.isNotEmpty(cacheManager)) + cacheManager.shutdown(); + LogUtil.info("DataEase is stopping"); + } +} diff --git a/backend/src/main/java/io/dataease/listener/util/CacheUtils.java b/backend/src/main/java/io/dataease/listener/util/CacheUtils.java index 22ebed424a..9a4fd3aa88 100644 --- a/backend/src/main/java/io/dataease/listener/util/CacheUtils.java +++ b/backend/src/main/java/io/dataease/listener/util/CacheUtils.java @@ -66,6 +66,12 @@ public class CacheUtils { return cache(cacheName).remove(key); } + public static void flush(String cacheName) { + CacheManager manager = getCacheManager(); + if (manager instanceof RedisCacheManager) return; + cache(cacheName).flush(); + } + public static void removeAll(String cacheName) { if (getCacheManager() instanceof RedisCacheManager) { org.springframework.cache.Cache cache = getCacheManager().getCache(cacheName); diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index fb4ea88283..76916b2905 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -844,22 +844,37 @@ public class ChartViewService { // 下钻 List drillFilters = new ArrayList<>(); boolean isDrill = false; - List drillRequest = chartExtRequest.getDrill(); - if (CollectionUtils.isNotEmpty(drillRequest) && (drill.size() > drillRequest.size())) { - for (int i = 0; i < drillRequest.size(); i++) { - ChartDrillRequest request = drillRequest.get(i); - for (ChartDimensionDTO dto : request.getDimensionList()) { - ChartViewFieldDTO chartViewFieldDTO = drill.get(i); + List drillRequestList = chartExtRequest.getDrill(); + if (CollectionUtils.isNotEmpty(drillRequestList) && (drill.size() > drillRequestList.size())) { +// 如果是从子维度开始下钻,那么先把主维度的条件先加上去 + if (CollectionUtils.isNotEmpty(xAxisExt) && StringUtils.equalsIgnoreCase(drill.get(0).getId(),xAxisExt.get(0).getId())) { + ChartDrillRequest head = drillRequestList.get(0); + for (int i = 0; i < xAxisBase.size(); i++) { + ChartDimensionDTO dimensionDTO = head.getDimensionList().get(i); + DatasetTableField datasetTableField = dataSetTableFieldsService.get(dimensionDTO.getId()); + ChartExtFilterRequest tmp = new ChartExtFilterRequest(); + tmp.setFieldId(tmp.getFieldId()); + tmp.setValue(Collections.singletonList(dimensionDTO.getValue())); + tmp.setOperator("in"); + tmp.setDatasetTableField(datasetTableField); + extFilterList.add(tmp); + drillFilters.add(tmp); + } + } + for (int i = 0; i < drillRequestList.size(); i++) { + ChartDrillRequest request = drillRequestList.get(i); + ChartViewFieldDTO chartViewFieldDTO = drill.get(i); + for (ChartDimensionDTO requestDimension : request.getDimensionList()) { // 将钻取值作为条件传递,将所有钻取字段作为xAxis并加上下一个钻取字段 - if (StringUtils.equalsIgnoreCase(dto.getId(), chartViewFieldDTO.getId())) { + if (StringUtils.equalsIgnoreCase(requestDimension.getId(), chartViewFieldDTO.getId())) { isDrill = true; - DatasetTableField datasetTableField = dataSetTableFieldsService.get(dto.getId()); + DatasetTableField datasetTableField = dataSetTableFieldsService.get(requestDimension.getId()); ChartViewFieldDTO d = new ChartViewFieldDTO(); BeanUtils.copyBean(d, datasetTableField); ChartExtFilterRequest drillFilter = new ChartExtFilterRequest(); - drillFilter.setFieldId(dto.getId()); - drillFilter.setValue(Collections.singletonList(dto.getValue())); + drillFilter.setFieldId(requestDimension.getId()); + drillFilter.setValue(Collections.singletonList(requestDimension.getValue())); drillFilter.setOperator("in"); drillFilter.setDatasetTableField(datasetTableField); extFilterList.add(drillFilter); @@ -869,7 +884,8 @@ public class ChartViewService { if (!checkDrillExist(xAxis, extStack, d, view)) { xAxis.add(d); } - if (i == drillRequest.size() - 1) { +// + if (i == drillRequestList.size() - 1) { ChartViewFieldDTO nextDrillField = drill.get(i + 1); if (!checkDrillExist(xAxis, extStack, nextDrillField, view)) { // get drill list first element's sort,then assign to nextDrillField diff --git a/backend/src/main/resources/ehcache/ehcache.xml b/backend/src/main/resources/ehcache/ehcache.xml index 5976911a62..144cdb7ad6 100644 --- a/backend/src/main/resources/ehcache/ehcache.xml +++ b/backend/src/main/resources/ehcache/ehcache.xml @@ -272,12 +272,16 @@ + timeToIdleSeconds="28800" + timeToLiveSeconds="28800" + memoryStoreEvictionPolicy="LRU" + diskPersistent="true"> + + diff --git a/frontend/src/components/widget/deWidget/DeTabs.vue b/frontend/src/components/widget/deWidget/DeTabs.vue index 3e9fe23856..786622fa4e 100644 --- a/frontend/src/components/widget/deWidget/DeTabs.vue +++ b/frontend/src/components/widget/deWidget/DeTabs.vue @@ -411,6 +411,10 @@ export default { const _this = this _this.$nextTick(() => { try { + const targetRef = _this.$refs['canvasTabRef-' + _this.activeTabName] + if (targetRef) { + targetRef[0].restore() + } _this.$refs[this.activeTabName][0].resizeChart() } catch (e) { // ignore diff --git a/frontend/src/icons/svg/icon_info_filled.svg b/frontend/src/icons/svg/icon_info_filled.svg new file mode 100644 index 0000000000..34439a4850 --- /dev/null +++ b/frontend/src/icons/svg/icon_info_filled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/icons/svg/icon_info_outlined.svg b/frontend/src/icons/svg/icon_info_outlined.svg new file mode 100644 index 0000000000..eebdd2f505 --- /dev/null +++ b/frontend/src/icons/svg/icon_info_outlined.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/views/chart/components/dragItem/components/FieldErrorTips.vue b/frontend/src/views/chart/components/dragItem/components/FieldErrorTips.vue index 8f184ef6bc..30e56d3d1c 100644 --- a/frontend/src/views/chart/components/dragItem/components/FieldErrorTips.vue +++ b/frontend/src/views/chart/components/dragItem/components/FieldErrorTips.vue @@ -6,7 +6,7 @@ :content="$t('chart.field_error_tips')" placement="bottom" > - + diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue index 48c63a2925..82756d5a20 100644 --- a/frontend/src/views/chart/view/ChartEdit.vue +++ b/frontend/src/views/chart/view/ChartEdit.vue @@ -28,11 +28,7 @@ :data="view" :tab-status="tabStatus" /> - + {{ $t('dataset.excel_info_3') }} - + - + - + - + @@ -118,7 +118,7 @@ :content="$t('system_parameter_setting.to_enable_tsl')" placement="top" > - + diff --git a/frontend/src/views/system/user/index.vue b/frontend/src/views/system/user/index.vue index a45d78fb37..c1f4fc52f2 100644 --- a/frontend/src/views/system/user/index.vue +++ b/frontend/src/views/system/user/index.vue @@ -261,7 +261,7 @@ popper-class="reset-pwd" trigger="click" > - +
{{ $t('user.recover_pwd') }}