Merge pull request #4609 from dataease/dev

merge dev
This commit is contained in:
fit2cloudrd 2023-02-23 09:50:33 +08:00 committed by GitHub
commit 7c04ff3193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 115 additions and 162 deletions

View File

@ -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;

View File

@ -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;
}
/**
* 对跨域提供支持
*/

View File

@ -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();
}
}

View File

@ -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) {

View File

@ -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<ContextClosedEvent> {
@Autowired(required = false)
CacheManager cacheManager;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
if (ObjectUtils.isNotEmpty(cacheManager))
cacheManager.shutdown();
LogUtil.info("DataEase is stopping");
}
}

View File

@ -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);

View File

@ -844,22 +844,37 @@ public class ChartViewService {
// 下钻
List<ChartExtFilterRequest> drillFilters = new ArrayList<>();
boolean isDrill = false;
List<ChartDrillRequest> 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<ChartDrillRequest> 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

View File

@ -272,12 +272,16 @@
<cache
name="sys_token_store"
eternal="true"
maxElementsInMemory="1"
maxElementsOnDisk="0"
eternal="false"
maxElementsInMemory="5000"
maxElementsOnDisk="50000"
overflowToDisk="true"
diskPersistent="true"
/>
timeToIdleSeconds="28800"
timeToLiveSeconds="28800"
memoryStoreEvictionPolicy="LRU"
diskPersistent="true">
<BootstrapCacheLoaderFactory class="net.sf.ehcache.store.DiskStoreBootstrapCacheLoaderFactory" properties="bootstrapAsynchronously=true" />
</cache>

View File

@ -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

View File

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23Z"/>
<path d="M12 5.5C12.6903 5.5 13.25 6.05965 13.25 6.75C13.25 7.44035 12.6903 8 12 8C11.3097 8 10.75 7.44035 10.75 6.75C10.75 6.05965 11.3097 5.5 12 5.5Z" fill="white"/>
<path d="M12.25 9H10.75C10.4739 9 10.25 9.22386 10.25 9.5V10.5C10.25 10.7761 10.4739 11 10.75 11H11.25V16H10C9.72386 16 9.5 16.2239 9.5 16.5V17.5C9.5 17.7761 9.72386 18 10 18H14.5C14.7761 18 15 17.7761 15 17.5V16.5C15 16.2239 14.7761 16 14.5 16H13.25V10C13.25 9.44772 12.8023 9 12.25 9Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 688 B

View File

@ -0,0 +1,12 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3234_102287)">
<path d="M12 5.5C12.6903 5.5 13.25 6.05965 13.25 6.75C13.25 7.44035 12.6903 8 12 8C11.3097 8 10.75 7.44035 10.75 6.75C10.75 6.05965 11.3097 5.5 12 5.5Z"/>
<path d="M12.25 9H10.75C10.4739 9 10.25 9.22386 10.25 9.5V10.5C10.25 10.7761 10.4739 11 10.75 11H11.25V16H10C9.72386 16 9.5 16.2239 9.5 16.5V17.5C9.5 17.7761 9.72386 18 10 18H14.5C14.7761 18 15 17.7761 15 17.5V16.5C15 16.2239 14.7761 16 14.5 16H13.25V10C13.25 9.44772 12.8023 9 12.25 9Z" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 22.9998C5.925 22.9998 1 18.0748 1 11.9998C1 5.92476 5.925 0.999756 12 0.999756C18.075 0.999756 23 5.92476 23 11.9998C23 18.0748 18.075 22.9998 12 22.9998ZM12 20.9998C16.9705 20.9998 21 16.9703 21 11.9998C21 7.02926 16.9705 2.99976 12 2.99976C7.0295 2.99976 3 7.02926 3 11.9998C3 16.9703 7.0295 20.9998 12 20.9998Z"/>
</g>
<defs>
<clipPath id="clip0_3234_102287">
<rect width="24" height="24" rx="4"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -6,7 +6,7 @@
:content="$t('chart.field_error_tips')"
placement="bottom"
>
<span><i class="el-icon-warning" /></span>
<span><svg-icon icon-class="icon_info_filled" /></span>
</el-tooltip>
</div>
</template>

View File

@ -28,11 +28,7 @@
:data="view"
:tab-status="tabStatus"
/>
<i
slot="reference"
class="el-icon-warning icon-class"
style="position:absolute; margin-left: 30px; top:14px;cursor: pointer;"
/>
<svg-icon slot="reference" class="icon-class" style="position:absolute; margin-left: 30px; top:14px;cursor: pointer;" icon-class="icon_info_filled" />
</el-popover>
<span
class="title-text view-title-name"

View File

@ -26,7 +26,7 @@
{{ $t('dataset.excel_info_2') }}<br>
{{ $t('dataset.excel_info_3') }}
</div>
<i class="el-icon-warning-outline"/> </el-tooltip></span>
<svg-icon icon-class="icon_info_outlined" /></el-tooltip></span>
<i
class="el-icon-d-arrow-left"
@click="showLeft = false"

View File

@ -454,7 +454,7 @@
:content="$t('commons.parameter_effect')"
placement="top"
>
<i class="el-icon-warning"/>
<svg-icon icon-class="icon_info_filled" />
</el-tooltip>
</template>
<template slot-scope="scope">

View File

@ -48,10 +48,7 @@
:data="table"
:tab-status="tabStatus"
/>
<i
slot="reference"
class="el-icon-warning-outline detail"
/>
<svg-icon slot="reference" class="detail" icon-class="icon_info_outlined" />
</el-popover>
</el-col>
<el-col

View File

@ -77,11 +77,7 @@
trigger="click"
>
<panel-detail-info />
<i
slot="reference"
class="el-icon-warning-outline icon-class"
style="margin-left: 4px;cursor: pointer;font-size: 14px;"
/>
<svg-icon slot="reference" style="margin-left: 4px;cursor: pointer;font-size: 14px;" class="icon-class" icon-class="icon_info_outlined" />
</el-popover>
</el-col>
<el-col :span="12">

View File

@ -71,7 +71,7 @@
popper-class="api-table-delete"
trigger="click"
>
<i :disabled="disabled" class="el-icon-warning" />
<svg-icon :disabled="disabled" icon-class="icon_info_filled" />
<div class="tips">
{{ $t('datasource.delete_this_item') }}
</div>

View File

@ -47,7 +47,7 @@
:content="$t('system_parameter_setting.front_time_out')"
placement="top"
>
<i class="el-icon-warning-outline tips" />
<svg-icon class="tips" icon-class="icon_info_outlined" />
</el-tooltip>
</template>
<el-input

View File

@ -90,7 +90,7 @@
:content="$t('system_parameter_setting.test_mail_recipient')"
placement="top"
>
<i class="el-icon-warning-outline tips-not-absolute" />
<svg-icon icon-class="icon_info_outlined" class="tips-not-absolute" />
</el-tooltip>
</template>
<dePwd
@ -106,7 +106,7 @@
:content="$t('system_parameter_setting.to_enable_ssl')"
placement="top"
>
<i class="el-icon-warning-outline tips-not-absolute" />
<svg-icon icon-class="icon_info_outlined" class="tips-not-absolute" />
</el-tooltip>
</el-checkbox>
@ -118,7 +118,7 @@
:content="$t('system_parameter_setting.to_enable_tsl')"
placement="top"
>
<i class="el-icon-warning-outline tips-not-absolute" />
<svg-icon icon-class="icon_info_outlined" class="tips-not-absolute" />
</el-tooltip>
</el-checkbox>
</el-form-item>

View File

@ -261,7 +261,7 @@
popper-class="reset-pwd"
trigger="click"
>
<i class="el-icon-warning" />
<svg-icon icon-class="icon_info_filled" />
<div class="tips">{{ $t('user.recover_pwd') }}</div>
<div class="editer-form-title">
<span