forked from github/dataease
commit
9c157603c1
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,6 +40,7 @@ yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.lh
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
|
@ -252,11 +252,11 @@
|
||||
<version>20171018</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<!--<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.13</version>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
<!-- 反射工具包 -->
|
||||
<dependency>
|
||||
<groupId>net.oneandone.reflections8</groupId>
|
||||
|
@ -4,9 +4,7 @@ import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.api.dto.LoginDto;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@ -46,4 +44,9 @@ public interface AuthApi {
|
||||
@PostMapping("/isOpenLdap")
|
||||
boolean isOpenLdap();
|
||||
|
||||
|
||||
@ApiOperation("是否开启oidc")
|
||||
@PostMapping("/isOpenOidc")
|
||||
boolean isOpenOidc();
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ public class TokenInfo implements Serializable {
|
||||
|
||||
private Long userId;
|
||||
|
||||
/* private String idToken; */
|
||||
|
||||
public String format(){
|
||||
return username + "," +userId;
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.authc.LogoutFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
|
@ -21,17 +21,19 @@ import io.dataease.plugins.util.PluginUtils;
|
||||
import io.dataease.plugins.xpack.ldap.dto.request.LdapValidateRequest;
|
||||
import io.dataease.plugins.xpack.ldap.dto.response.ValidateResult;
|
||||
import io.dataease.plugins.xpack.ldap.service.LdapXpackService;
|
||||
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@RestController
|
||||
public class AuthServer implements AuthApi {
|
||||
|
||||
@ -113,6 +115,13 @@ public class AuthServer implements AuthApi {
|
||||
@Override
|
||||
public String logout() {
|
||||
String token = ServletUtils.getToken();
|
||||
|
||||
if (isOpenOidc()) {
|
||||
HttpServletRequest request = ServletUtils.request();
|
||||
String idToken = request.getHeader("IdToken");
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
oidcXpackService.logout(idToken);
|
||||
}
|
||||
if (StringUtils.isEmpty(token) || StringUtils.equals("null", token) || StringUtils.equals("undefined", token)) {
|
||||
return "success";
|
||||
}
|
||||
@ -144,6 +153,15 @@ public class AuthServer implements AuthApi {
|
||||
return open;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpenOidc() {
|
||||
Boolean licValid = PluginUtils.licValid();
|
||||
if(!licValid) return false;
|
||||
return authUserService.supportOidc();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*@Override
|
||||
public Boolean isLogin() {
|
||||
return null;
|
||||
|
@ -23,6 +23,8 @@ public interface AuthUserService {
|
||||
|
||||
boolean supportLdap();
|
||||
|
||||
Boolean supportOidc();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import io.dataease.commons.constants.AuthConstants;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import io.dataease.plugins.xpack.ldap.service.LdapXpackService;
|
||||
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@ -19,6 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -107,8 +110,21 @@ public class AuthUserServiceImpl implements AuthUserService {
|
||||
|
||||
@Override
|
||||
public boolean supportLdap() {
|
||||
Map<String, LdapXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((LdapXpackService.class));
|
||||
if(beansOfType.keySet().size() == 0) return false;
|
||||
LdapXpackService ldapXpackService = SpringContextUtil.getBean(LdapXpackService.class);
|
||||
if(ObjectUtils.isEmpty(ldapXpackService)) return false;
|
||||
return ldapXpackService.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean supportOidc() {
|
||||
Map<String, OidcXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((OidcXpackService.class));
|
||||
if(beansOfType.keySet().size() == 0) return false;
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
if(ObjectUtils.isEmpty(oidcXpackService)) return false;
|
||||
return oidcXpackService.isSuuportOIDC();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -56,9 +56,15 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
// filterChainDefinitionMap.put("/axios.map", ANON);
|
||||
|
||||
filterChainDefinitionMap.put("/api/auth/login", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/logout", ANON);
|
||||
// filterChainDefinitionMap.put("/api/auth/logout", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/validateName", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/isOpenLdap", ANON);
|
||||
filterChainDefinitionMap.put("/api/auth/isOpenOidc", ANON);
|
||||
filterChainDefinitionMap.put("/api/pluginCommon/component/*", ANON);
|
||||
filterChainDefinitionMap.put("/plugin/oidc/authInfo", ANON);
|
||||
filterChainDefinitionMap.put("/sso/callBack*", ANON);
|
||||
|
||||
|
||||
filterChainDefinitionMap.put("/unauth", ANON);
|
||||
filterChainDefinitionMap.put("/display/**", ANON);
|
||||
filterChainDefinitionMap.put("/tokenExpired", ANON);
|
||||
|
@ -2,16 +2,18 @@ package io.dataease.auth.util;
|
||||
|
||||
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;
|
||||
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
import io.dataease.exception.DataEaseException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
@ -34,10 +36,13 @@ public class JWTUtils {
|
||||
*/
|
||||
public static boolean verify(String token, TokenInfo tokenInfo, String secret) {
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
JWTVerifier verifier = JWT.require(algorithm)
|
||||
Verification verification = JWT.require(algorithm)
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId())
|
||||
.build();
|
||||
.withClaim("userId", tokenInfo.getUserId());
|
||||
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
|
||||
verification.withClaim("idToken", tokenInfo.getIdToken());
|
||||
} */
|
||||
JWTVerifier verifier = verification.build();
|
||||
verifier.verify(token);
|
||||
return true;
|
||||
}
|
||||
@ -50,10 +55,15 @@ public class JWTUtils {
|
||||
DecodedJWT jwt = JWT.decode(token);
|
||||
String username = jwt.getClaim("username").asString();
|
||||
Long userId = jwt.getClaim("userId").asLong();
|
||||
// String idToken = jwt.getClaim("idToken").asString();
|
||||
if (StringUtils.isEmpty(username) || ObjectUtils.isEmpty(userId) ){
|
||||
DataEaseException.throwException("token格式错误!");
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().username(username).userId(userId).build();
|
||||
TokenInfoBuilder tokenInfoBuilder = TokenInfo.builder().username(username).userId(userId);
|
||||
/* if (StringUtils.isNotBlank(idToken)) {
|
||||
tokenInfoBuilder.idToken(idToken);
|
||||
} */
|
||||
TokenInfo tokenInfo = tokenInfoBuilder.build();
|
||||
return tokenInfo;
|
||||
}
|
||||
|
||||
@ -107,12 +117,14 @@ public class JWTUtils {
|
||||
try {
|
||||
Date date = new Date(System.currentTimeMillis()+EXPIRE_TIME);
|
||||
Algorithm algorithm = Algorithm.HMAC256(secret);
|
||||
// 附带username信息
|
||||
return JWT.create()
|
||||
Builder builder = JWT.create()
|
||||
.withClaim("username", tokenInfo.getUsername())
|
||||
.withClaim("userId", tokenInfo.getUserId())
|
||||
.withExpiresAt(date)
|
||||
.sign(algorithm);
|
||||
.withClaim("userId", tokenInfo.getUserId());
|
||||
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
|
||||
builder.withClaim("idToken", tokenInfo.getIdToken());
|
||||
} */
|
||||
return builder.withExpiresAt(date).sign(algorithm);
|
||||
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
@ -45,9 +45,12 @@ public class DefaultLicenseService {
|
||||
}
|
||||
return f2CLicenseResponse;
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return F2CLicenseResponse.invalid(e.getMessage());
|
||||
LogUtil.error(e.getMessage());
|
||||
// e.printStackTrace();
|
||||
// return F2CLicenseResponse.invalid(e.getMessage());
|
||||
return F2CLicenseResponse.noRecord();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@ package io.dataease.plugins.config;
|
||||
|
||||
import io.dataease.base.domain.MyPlugin;
|
||||
import io.dataease.plugins.loader.ClassloaderResponsity;
|
||||
import io.dataease.plugins.loader.ControllerLoader;
|
||||
import io.dataease.plugins.loader.ModuleClassLoader;
|
||||
import io.dataease.plugins.loader.MybatisLoader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -19,6 +20,9 @@ public class LoadjarUtil {
|
||||
@Autowired
|
||||
private MybatisLoader mybatisLoader;
|
||||
|
||||
@Autowired
|
||||
private ControllerLoader controllerLoader;
|
||||
|
||||
public List<?> loadJar(String jarPath, MyPlugin myPlugin) throws Exception{
|
||||
File jar = new File(jarPath);
|
||||
URI uri = jar.toURI();
|
||||
@ -34,6 +38,10 @@ public class LoadjarUtil {
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
classLoader.initBean();
|
||||
mybatisLoader.loadMybatis(myPlugin);
|
||||
|
||||
List<String> controllers = classLoader.getRegisteredController();
|
||||
controllerLoader.registerController(controllers);
|
||||
|
||||
ClassloaderResponsity.getInstance().addClassLoader(moduleName,classLoader);
|
||||
|
||||
|
||||
|
@ -0,0 +1,95 @@
|
||||
package io.dataease.plugins.loader;
|
||||
|
||||
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class ControllerLoader {
|
||||
|
||||
/**
|
||||
* 去掉Controller的Mapping
|
||||
* @param controllerBeanName
|
||||
*/
|
||||
private void unregisterController(String controllerBeanName){
|
||||
final RequestMappingHandlerMapping requestMappingHandlerMapping=(RequestMappingHandlerMapping)SpringContextUtil.getBean("requestMappingHandlerMapping");
|
||||
|
||||
if(requestMappingHandlerMapping!=null){
|
||||
String handler=controllerBeanName;
|
||||
Object controller= SpringContextUtil.getBean(handler);
|
||||
if(controller==null){
|
||||
return;
|
||||
}
|
||||
final Class<?> targetClass=controller.getClass();
|
||||
ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
|
||||
public void doWith(Method method) {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
try {
|
||||
Method createMappingMethod = RequestMappingHandlerMapping.class.
|
||||
getDeclaredMethod("getMappingForMethod", Method.class, Class.class);
|
||||
createMappingMethod.setAccessible(true);
|
||||
RequestMappingInfo requestMappingInfo =(RequestMappingInfo)
|
||||
createMappingMethod.invoke(requestMappingHandlerMapping,specificMethod,targetClass);
|
||||
if(requestMappingInfo != null) {
|
||||
requestMappingHandlerMapping.unregisterMapping(requestMappingInfo);
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册Controller
|
||||
* @param controllerBeanName
|
||||
* @throws Exception
|
||||
*/
|
||||
private void registerController(String controllerBeanName) throws Exception{
|
||||
final RequestMappingHandlerMapping requestMappingHandlerMapping=(RequestMappingHandlerMapping) SpringContextUtil.getBean("requestMappingHandlerMapping");
|
||||
|
||||
if(requestMappingHandlerMapping!=null){
|
||||
String handler=controllerBeanName;
|
||||
Object controller= SpringContextUtil.getBean(handler);
|
||||
if(controller==null){
|
||||
return;
|
||||
}
|
||||
unregisterController(controllerBeanName);
|
||||
//注册Controller
|
||||
Method method=requestMappingHandlerMapping.getClass().getSuperclass().getSuperclass().getDeclaredMethod("detectHandlerMethods",Object.class);
|
||||
|
||||
method.setAccessible(true);
|
||||
method.invoke(requestMappingHandlerMapping,handler);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerController(List<String> beanNames) {
|
||||
beanNames.forEach(name -> {
|
||||
try {
|
||||
registerController(name);
|
||||
} catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
LogUtil.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -7,10 +7,14 @@ import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.type.TypeAliasRegistry;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -35,6 +39,8 @@ public class ModuleClassLoader extends URLClassLoader {
|
||||
//需要注册的spring bean的name集合
|
||||
private List<String> registeredBean = new ArrayList<>();
|
||||
|
||||
private List<String> registeredController = new ArrayList<>();
|
||||
|
||||
|
||||
//构造
|
||||
public ModuleClassLoader(URL[] urls, ClassLoader parent) {
|
||||
@ -150,8 +156,12 @@ public class ModuleClassLoader extends URLClassLoader {
|
||||
beanName = StringUtils.uncapitalize(beanName);
|
||||
|
||||
SpringContextUtil.getBeanFactory().registerBeanDefinition(beanName,beanDefinition);
|
||||
|
||||
if (isHandler(cla)) {
|
||||
registeredController.add(beanName);
|
||||
}
|
||||
|
||||
registeredBean.add(beanName);
|
||||
// System.out.println("注册bean:"+beanName);
|
||||
}
|
||||
|
||||
}
|
||||
@ -164,6 +174,10 @@ public class ModuleClassLoader extends URLClassLoader {
|
||||
return registeredBean;
|
||||
}
|
||||
|
||||
public List<String> getRegisteredController() {
|
||||
return registeredController;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 方法描述 判断class对象是否带有spring的注解
|
||||
@ -184,6 +198,9 @@ public class ModuleClassLoader extends URLClassLoader {
|
||||
if( Modifier.isAbstract(cla.getModifiers())){
|
||||
return false;
|
||||
}
|
||||
if (isHandler(cla)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(cla.getAnnotation(Component.class)!=null){
|
||||
return true;
|
||||
@ -194,8 +211,15 @@ public class ModuleClassLoader extends URLClassLoader {
|
||||
if(cla.getAnnotation(Service.class)!=null){
|
||||
return true;
|
||||
}
|
||||
if(cla.getAnnotation(Service.class)!=null){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isHandler(Class<?> beanType) {
|
||||
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.dataease.plugins.server;
|
||||
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import io.dataease.plugins.common.dto.PluginSysMenu;
|
||||
import io.dataease.plugins.common.service.PluginComponentService;
|
||||
import io.dataease.plugins.common.service.PluginMenuService;
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -9,7 +10,6 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import springfox.documentation.annotations.ApiIgnore;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
public class PluginCommonServer {
|
||||
|
||||
@GetMapping("/async/{menuId}")
|
||||
public void componentInfo(@PathVariable Long menuId) {
|
||||
public void menuInfo(@PathVariable Long menuId) {
|
||||
Map<String, PluginMenuService> pluginMenuServiceMap = SpringContextUtil.getApplicationContext().getBeansOfType(PluginMenuService.class);
|
||||
pluginMenuServiceMap.values().stream().forEach(service -> {
|
||||
AtomicReference<PluginSysMenu> atomicReference = new AtomicReference<>();
|
||||
@ -65,4 +65,41 @@ public class PluginCommonServer {
|
||||
return;
|
||||
});
|
||||
}
|
||||
|
||||
@GetMapping("/component/{componentName}")
|
||||
public void componentInfo(@PathVariable String componentName) {
|
||||
Map<String, PluginComponentService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType(PluginComponentService.class);
|
||||
beansOfType.values().stream().forEach(service -> {
|
||||
List<String> components = service.components();
|
||||
if (components.contains(componentName)) {
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
BufferedInputStream bis = null;
|
||||
InputStream inputStream = null;
|
||||
OutputStream os = null; //输出流
|
||||
try{
|
||||
inputStream = service.vueResource(componentName);
|
||||
byte[] buffer = new byte[1024];
|
||||
os = response.getOutputStream();
|
||||
bis = new BufferedInputStream(inputStream);
|
||||
int i = bis.read(buffer);
|
||||
while(i != -1){
|
||||
os.write(buffer, 0, i);
|
||||
i = bis.read(buffer);
|
||||
}
|
||||
os.flush();
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}finally {
|
||||
try {
|
||||
bis.close();
|
||||
inputStream.close();
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
package io.dataease.plugins.server;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.exception.DEException;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.commons.utils.ServletUtils;
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
|
||||
import io.dataease.plugins.xpack.oidc.dto.SSOToken;
|
||||
import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo;
|
||||
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
|
||||
import io.dataease.service.sys.SysUserService;
|
||||
|
||||
@RequestMapping("/sso")
|
||||
@Controller
|
||||
public class SSOServer {
|
||||
|
||||
@Autowired
|
||||
private AuthUserService authUserService;
|
||||
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@GetMapping("/callBack")
|
||||
public ModelAndView callBack(@RequestParam("code") String code, @RequestParam("state") String state) {
|
||||
Map<String, OidcXpackService> beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((OidcXpackService.class));
|
||||
if(beansOfType.keySet().size() == 0) {
|
||||
DEException.throwException("缺少oidc插件");
|
||||
}
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
Boolean suuportOIDC = oidcXpackService.isSuuportOIDC();
|
||||
if (!suuportOIDC) {
|
||||
DEException.throwException("未开启oidc");
|
||||
}
|
||||
Map<String, String> config = config(oidcXpackService);
|
||||
SSOToken ssoToken = oidcXpackService.requestSsoToken(config, code, state);
|
||||
|
||||
SSOUserInfo ssoUserInfo = oidcXpackService.requestUserInfo(config, ssoToken.getAccessToken());
|
||||
SysUserEntity sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName());
|
||||
if(null == sysUserEntity){
|
||||
sysUserService.saveOIDCUser(ssoUserInfo);
|
||||
sysUserEntity = authUserService.getUserByName(ssoUserInfo.getUserName());
|
||||
}
|
||||
TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build();
|
||||
String realPwd = CodingUtil.md5(sysUserService.defaultPWD());
|
||||
String token = JWTUtils.sign(tokenInfo, realPwd);
|
||||
ServletUtils.setToken(token);
|
||||
HttpServletResponse response = ServletUtils.response();
|
||||
|
||||
Cookie cookie_token = new Cookie("Authorization", token);cookie_token.setPath("/");
|
||||
Cookie cookie_id_token = new Cookie("IdToken", ssoToken.getIdToken());cookie_id_token.setPath("/");
|
||||
Cookie cookie_ac_token = new Cookie("AccessToken", ssoToken.getAccessToken());cookie_ac_token.setPath("/");
|
||||
|
||||
response.addCookie(cookie_token);
|
||||
response.addCookie(cookie_id_token);
|
||||
response.addCookie(cookie_ac_token);
|
||||
ModelAndView modelAndView = new ModelAndView("redirect:/");
|
||||
return modelAndView;
|
||||
}
|
||||
private Map<String, String> config(OidcXpackService oidcXpackService) {
|
||||
List<SysSettingDto> sysSettingDtos = oidcXpackService.oidcSettings();
|
||||
Map<String, String> config = sysSettingDtos.stream().collect(Collectors.toMap(SysSettingDto::getParamKey, SysSettingDto::getParamValue));
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RequestMapping("/api/ldap")
|
||||
@RequestMapping("/plugin/ldap")
|
||||
@RestController
|
||||
public class XLdapServer {
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
package io.dataease.plugins.server;
|
||||
|
||||
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
|
||||
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RequestMapping("/plugin/oidc")
|
||||
@RestController
|
||||
public class XOidcServer {
|
||||
|
||||
|
||||
@PostMapping("/info")
|
||||
public List<SysSettingDto> getOidcInfo() {
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
return oidcXpackService.oidcSettings();
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public void save(@RequestBody List<SysSettingDto> settings) {
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
oidcXpackService.save(settings);
|
||||
}
|
||||
|
||||
@PostMapping(value="/authInfo")
|
||||
public Map<String, Object> authInfo() {
|
||||
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
List<SysSettingDto> oidcSettings = oidcXpackService.oidcSettings();
|
||||
|
||||
Map<String, String> authParam = new HashMap<>();
|
||||
authParam.put("response_type", "code");
|
||||
authParam.put("state", "state");
|
||||
// authParam.put("redirect_uri", "http://localhost:9528");
|
||||
|
||||
|
||||
oidcSettings.forEach(param -> {
|
||||
if(StringUtils.isNotBlank(param.getParamKey())) {
|
||||
if (StringUtils.equals(param.getParamKey(), "oidc.authEndpoint")) {
|
||||
result.put("authEndpoint", param.getParamValue());
|
||||
}
|
||||
if (StringUtils.equals(param.getParamKey(), "oidc.scope")) {
|
||||
authParam.put("scope", param.getParamValue());
|
||||
}
|
||||
if (StringUtils.equals(param.getParamKey(), "oidc.clientId")) {
|
||||
authParam.put("client_id", param.getParamValue());
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
result.put("authParam", authParam);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -208,7 +208,9 @@ public class ChartViewService {
|
||||
customFilter.addAll(collect);
|
||||
}
|
||||
|
||||
if (StringUtils.equalsIgnoreCase("text", view.getType()) || StringUtils.equalsIgnoreCase("gauge", view.getType())) {
|
||||
if (StringUtils.equalsIgnoreCase("text", view.getType())
|
||||
|| StringUtils.equalsIgnoreCase("gauge", view.getType())
|
||||
|| StringUtils.equalsIgnoreCase("liquid", view.getType())) {
|
||||
xAxis = new ArrayList<>();
|
||||
if (CollectionUtils.isEmpty(yAxis)) {
|
||||
ChartViewDTO dto = new ChartViewDTO();
|
||||
@ -458,6 +460,9 @@ public class ChartViewService {
|
||||
map.putAll(mapChart);
|
||||
map.putAll(mapTableNormal);
|
||||
|
||||
List<DatasetTableField> sourceFields = dataSetTableFieldsService.getFieldsByTableId(view.getTableId());
|
||||
map.put("sourceFields",sourceFields);
|
||||
|
||||
ChartViewDTO dto = new ChartViewDTO();
|
||||
BeanUtils.copyBean(dto, view);
|
||||
dto.setData(map);
|
||||
|
@ -22,6 +22,8 @@ import io.dataease.controller.sys.response.SysUserGridResponse;
|
||||
import io.dataease.controller.sys.response.SysUserRole;
|
||||
import io.dataease.i18n.Translator;
|
||||
import io.dataease.plugins.common.entity.XpackLdapUserEntity;
|
||||
import io.dataease.plugins.xpack.oidc.dto.SSOUserInfo;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -31,6 +33,8 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -82,6 +86,7 @@ public class SysUserService {
|
||||
@Transactional
|
||||
public int save(SysUserCreateRequest request) {
|
||||
checkUsername(request);
|
||||
checkEmail(request);
|
||||
SysUser user = BeanUtils.copyBean(new SysUser(), request);
|
||||
long now = System.currentTimeMillis();
|
||||
user.setCreateTime(now);
|
||||
@ -102,6 +107,33 @@ public class SysUserService {
|
||||
return insert;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void saveOIDCUser(SSOUserInfo ssoUserInfo) {
|
||||
long now = System.currentTimeMillis();
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUsername(ssoUserInfo.getUserName());
|
||||
sysUser.setNickName(ssoUserInfo.getNickName());
|
||||
sysUser.setEmail(ssoUserInfo.getEmail());
|
||||
sysUser.setPassword(CodingUtil.md5(DEFAULT_PWD));
|
||||
sysUser.setCreateTime(now);
|
||||
sysUser.setUpdateTime(now);
|
||||
sysUser.setEnabled(1L);
|
||||
sysUser.setLanguage("zh_CN");
|
||||
sysUser.setFrom(2);
|
||||
sysUserMapper.insert(sysUser);
|
||||
SysUser dbUser = findOne(sysUser);
|
||||
if (null != dbUser && null != dbUser.getUserId()) {
|
||||
// oidc默认角色是普通员工
|
||||
List<Long> roleIds = new ArrayList<Long>();
|
||||
roleIds.add(2L);
|
||||
saveUserRoles( dbUser.getUserId(), roleIds);
|
||||
}
|
||||
}
|
||||
|
||||
public String defaultPWD() {
|
||||
return DEFAULT_PWD;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void saveLdapUsers(LdapAddRequest request) {
|
||||
long now = System.currentTimeMillis();
|
||||
@ -115,6 +147,7 @@ public class SysUserService {
|
||||
sysUser.setCreateTime(now);
|
||||
sysUser.setUpdateTime(now);
|
||||
sysUser.setEnabled(request.getEnabled());
|
||||
sysUser.setLanguage("zh_CN");
|
||||
sysUser.setFrom(1);
|
||||
return sysUser;
|
||||
}).collect(Collectors.toList());
|
||||
@ -145,6 +178,7 @@ public class SysUserService {
|
||||
@Transactional
|
||||
public int update(SysUserCreateRequest request) {
|
||||
checkUsername(request);
|
||||
checkEmail(request);
|
||||
if (StringUtils.isEmpty(request.getPassword())) {
|
||||
request.setPassword(null);
|
||||
}
|
||||
@ -287,4 +321,19 @@ public class SysUserService {
|
||||
throw new RuntimeException(Translator.get("i18n_username_exists"));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEmail(SysUserCreateRequest request) {
|
||||
SysUserExample sysUserExample = new SysUserExample();
|
||||
SysUserExample.Criteria criteria = sysUserExample.createCriteria();
|
||||
if (request.getUserId() != null) {
|
||||
criteria.andUserIdNotEqualTo(request.getUserId());
|
||||
}
|
||||
criteria.andEmailEqualTo(request.getEmail());
|
||||
List<SysUser> sysUsers = sysUserMapper.selectByExample(sysUserExample);
|
||||
if (CollectionUtils.isNotEmpty(sysUsers)) {
|
||||
throw new RuntimeException(Translator.get("i18n_email_exists"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -243,6 +243,7 @@ i18n_union_field_exists=The same field can't in two dataset
|
||||
i18n_cron_time_error=Start time can't greater then end time
|
||||
i18n_auth_source_be_canceled=This Auth Resource Already Be Canceled,Please Connect Admin
|
||||
i18n_username_exists=ID is already exists
|
||||
i18n_email_exists=Email is already exists
|
||||
i18n_ds_name_exists=Datasource name used
|
||||
i18n_sync_job_exists=There is already a synchronization task running, please try again later
|
||||
i18n_datasource_check_fail=Invalid,please check config
|
||||
|
@ -233,7 +233,7 @@ i18n_chart_count=记录数*
|
||||
i18n_excel_have_merge_region=Excel 存在合并单元格
|
||||
i18n_cron_expression_error=Cron 表达式校验错误
|
||||
i18n_same_folder_can_not_repeat=同一目录下该名称已被使用
|
||||
i18n_select_diff_folder= 请选择不通的目录
|
||||
i18n_select_diff_folder= 请选择不同的目录
|
||||
i18n_default_panel=默认仪表板
|
||||
i18n_panel_list=仪表板
|
||||
i18n_processing_data=正在处理数据,稍后刷新
|
||||
@ -242,6 +242,7 @@ i18n_union_field_exists=两个数据集之间关联不能出现多次相同字
|
||||
i18n_cron_time_error=开始时间不能大于结束时间
|
||||
i18n_auth_source_be_canceled=本用户当前资源所有授权权限已经被取消,如需再次开通,请联系管理员
|
||||
i18n_username_exists=用户 ID 已存在
|
||||
i18n_email_exists=邮箱已存在
|
||||
i18n_ds_name_exists=数据源名称已被使用
|
||||
i18n_sync_job_exists=已经有同步任务在运行,稍后重试
|
||||
i18n_datasource_check_fail=校验失败,请检查配置信息
|
||||
|
@ -236,7 +236,7 @@ i18n_chart_count=記錄數*
|
||||
i18n_excel_have_merge_region=Excel存在合並單元格
|
||||
i18n_cron_expression_error=Cron表達式校驗錯誤
|
||||
i18n_same_folder_can_not_repeat=同一目錄下該名稱已被使用
|
||||
i18n_select_diff_folder= 请选择不通的目录
|
||||
i18n_select_diff_folder= 请选择不同的目录
|
||||
i18n_default_panel=默認儀表板
|
||||
i18n_panel_list=儀表板
|
||||
i18n_processing_data=正在處理數據,稍後刷新
|
||||
@ -245,6 +245,7 @@ i18n_union_field_exists=兩個數據集之間關聯不能出現多次相同字
|
||||
i18n_cron_time_error=開始時間不能大於結束時間
|
||||
i18n_auth_source_be_canceled=本用户当前资源所有授权权限已经被取消,如需再次开通,请联系管理员
|
||||
i18n_username_exists=用戶ID已存在
|
||||
i18n_email_exists=郵箱已存在
|
||||
i18n_ds_name_exists=數據源名稱已被使用
|
||||
i18n_sync_job_exists=已經有同步任務在運行,稍後重試
|
||||
i18n_datasource_check_fail=校驗失敗,請檢查配置信息
|
||||
|
@ -100,7 +100,7 @@ export function roleGrid(pageIndex, pageSize, data) {
|
||||
|
||||
export function ldapUsers(data) {
|
||||
return request({
|
||||
url: '/api/ldap/users',
|
||||
url: '/plugin/ldap/users',
|
||||
method: 'post',
|
||||
loading: true
|
||||
})
|
||||
|
@ -57,3 +57,10 @@ export function ldapStatus() {
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function oidcStatus() {
|
||||
return request({
|
||||
url: '/api/auth/isOpenOidc',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ export default {
|
||||
right: 178px;
|
||||
top: 8px;
|
||||
background: red;
|
||||
// color: #fff;
|
||||
color: #fff;
|
||||
border-radius: 17px;
|
||||
padding: 4px 7px;
|
||||
font-size: 16px;
|
||||
|
@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="showDrag"
|
||||
id="editor"
|
||||
class="editor"
|
||||
:class="[
|
||||
|
@ -49,6 +49,14 @@
|
||||
<el-input v-model="innerOpacity" type="number" size="mini" min="0" max="100" step="10" @change="styleChange" />
|
||||
</div>
|
||||
|
||||
<el-tooltip :content="$t('panel.borderRadius')">
|
||||
<i style="float: left;margin-top: 3px;margin-left: 2px;" class="icon iconfont icon-fangxing-" />
|
||||
</el-tooltip>
|
||||
|
||||
<div style="width: 70px;float: left;margin-top: 2px;margin-left: 2px;">
|
||||
<el-input v-model="styleInfo.borderRadius" type="number" size="mini" min="0" max="100" step="1" @change="styleChange" />
|
||||
</div>
|
||||
|
||||
<div style="width: 20px;float: left;margin-top: 2px;margin-left: 10px;">
|
||||
<div style="width: 16px;height: 18px">
|
||||
<el-tooltip :content="$t('panel.color')">
|
||||
@ -173,7 +181,7 @@ export default {
|
||||
ps = x + 60
|
||||
}
|
||||
// 防止toolbar超出边界
|
||||
const xGap = ps + 495 - this.canvasWidth
|
||||
const xGap = ps + 565 - this.canvasWidth
|
||||
// console.log('canvasWidth:' + this.canvasWidth + ';xGap:' + xGap)
|
||||
if (xGap > 0) {
|
||||
return ps - xGap
|
||||
@ -205,7 +213,7 @@ export default {
|
||||
.el-card-main {
|
||||
height: 34px;
|
||||
z-index: 10;
|
||||
width: 550px;
|
||||
width: 620px;
|
||||
position: absolute;
|
||||
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ export default {
|
||||
trackMenu() {
|
||||
const trackMenuInfo = []
|
||||
let linkageCount = 0
|
||||
this.chart.data && this.chart.data.fields && this.chart.data.fields.forEach(item => {
|
||||
this.chart.data && this.chart.data.sourceFields && this.chart.data.sourceFields.forEach(item => {
|
||||
const sourceInfo = this.chart.id + '#' + item.id
|
||||
if (this.nowPanelTrackInfo[sourceInfo]) {
|
||||
linkageCount++
|
||||
|
@ -57,8 +57,11 @@ const list = [
|
||||
fontWeight: 400,
|
||||
lineHeight: '',
|
||||
letterSpacing: 0,
|
||||
textAlign: 'left',
|
||||
color: '#000000'
|
||||
textAlign: 'center',
|
||||
color: '#000000',
|
||||
verticalAlign: 'middle',
|
||||
backgroundColor: '#ffffff',
|
||||
borderRadius: 0
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -130,6 +130,8 @@ export default {
|
||||
re_login: 'Login again'
|
||||
},
|
||||
commons: {
|
||||
search: 'Search',
|
||||
folder: 'Folder',
|
||||
no_target_permission: 'No permission',
|
||||
success: 'Success',
|
||||
switch_lang: 'Switch Language Success',
|
||||
|
@ -130,6 +130,8 @@ export default {
|
||||
re_login: '重新登陸'
|
||||
},
|
||||
commons: {
|
||||
search: '搜索',
|
||||
folder: '目录',
|
||||
no_target_permission: '沒有權限',
|
||||
success: '成功',
|
||||
switch_lang: '切換語言成功',
|
||||
|
@ -130,6 +130,8 @@ export default {
|
||||
re_login: '重新登录'
|
||||
},
|
||||
commons: {
|
||||
search: '搜索',
|
||||
folder: '目录',
|
||||
no_target_permission: '没有权限',
|
||||
success: '成功',
|
||||
switch_lang: '切换语言成功',
|
||||
@ -530,6 +532,15 @@ export default {
|
||||
mapping_cannot_be_empty: 'LDAP 用户属性映射不能为空',
|
||||
password_cannot_be_empty: 'LDAP 密码不能为空'
|
||||
},
|
||||
oidc: {
|
||||
auth_endpoint: '请输入AuthEndpoint',
|
||||
token_endpoint: '请输入TokenEndpoint',
|
||||
userinfo_endpoint: '请输入UserinfoEndpoint',
|
||||
logout_endpoint: '请输入logoutEndpoint',
|
||||
clientId: '请输入ClientId',
|
||||
secret: '请输入Secret',
|
||||
open: '启用OIDC认证'
|
||||
},
|
||||
role: {
|
||||
menu_authorization: '菜单授权',
|
||||
data_authorization: '数据授权',
|
||||
|
@ -5,15 +5,7 @@ import { DEFAULT_SIZE } from '@/views/chart/chart/chart'
|
||||
export function baseLiquid(plot, container, chart) {
|
||||
let value = 0
|
||||
const colors = []
|
||||
let max
|
||||
let radius
|
||||
let outlineBorder
|
||||
let outlineDistance
|
||||
let waveLength
|
||||
let waveCount
|
||||
let bgColor
|
||||
let shape
|
||||
let labelContent
|
||||
let max, radius, outlineBorder, outlineDistance, waveLength, waveCount, bgColor, shape, labelContent, title
|
||||
if (chart.data) {
|
||||
if (chart.data.series.length > 0) {
|
||||
value = chart.data.series[0].data[0].value
|
||||
@ -36,7 +28,7 @@ export function baseLiquid(plot, container, chart) {
|
||||
max = size.liquidMax ? size.liquidMax : DEFAULT_SIZE.liquidMax
|
||||
radius = parseFloat((size.liquidSize ? size.liquidSize : DEFAULT_SIZE.liquidSize) / 100)
|
||||
outlineBorder = parseInt(size.liquidOutlineBorder ? size.liquidOutlineBorder : DEFAULT_SIZE.liquidOutlineBorder)
|
||||
outlineDistance = parseInt(size.liquidOutlineDistance ? size.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance)
|
||||
outlineDistance = parseInt((size.liquidOutlineDistance || size.liquidOutlineDistance === 0) ? size.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance)
|
||||
waveLength = parseInt(size.liquidWaveLength ? size.liquidWaveLength : DEFAULT_SIZE.liquidWaveLength)
|
||||
waveCount = parseInt(size.liquidWaveCount ? size.liquidWaveCount : DEFAULT_SIZE.liquidWaveCount)
|
||||
shape = size.liquidShape ? size.liquidShape : DEFAULT_SIZE.liquidShape
|
||||
@ -62,6 +54,22 @@ export function baseLiquid(plot, container, chart) {
|
||||
if (customStyle.background) {
|
||||
bgColor = customStyle.background.color.concat(digToHex(parseInt(customStyle.background.alpha)))
|
||||
}
|
||||
if (customStyle.text) {
|
||||
const t = JSON.parse(JSON.stringify(customStyle.text))
|
||||
if (t.show) {
|
||||
title = {
|
||||
formatter: () => { return chart.title },
|
||||
style: ({ percent }) => ({
|
||||
fontSize: parseInt(t.fontSize),
|
||||
color: t.color,
|
||||
fontWeight: t.isBolder ? 'bold' : 'normal',
|
||||
fontStyle: t.isItalic ? 'italic' : 'normal'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
title = false
|
||||
}
|
||||
}
|
||||
}
|
||||
// 开始渲染
|
||||
if (plot) {
|
||||
@ -87,6 +95,7 @@ export function baseLiquid(plot, container, chart) {
|
||||
count: waveCount
|
||||
},
|
||||
statistic: {
|
||||
title: title,
|
||||
content: labelContent
|
||||
}
|
||||
})
|
||||
|
@ -24,14 +24,14 @@
|
||||
<el-form-item :label="$t('chart.text_color')" class="form-item">
|
||||
<el-color-picker v-model="titleForm.color" class="color-picker-style" @change="changeTitleStyle" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.text_h_position')" class="form-item">
|
||||
<el-form-item v-show="chart.type && chart.type !== 'liquid'" :label="$t('chart.text_h_position')" class="form-item">
|
||||
<el-radio-group v-model="titleForm.hPosition" size="mini" @change="changeTitleStyle">
|
||||
<el-radio-button label="left">{{ $t('chart.text_pos_left') }}</el-radio-button>
|
||||
<el-radio-button label="center">{{ $t('chart.text_pos_center') }}</el-radio-button>
|
||||
<el-radio-button label="right">{{ $t('chart.text_pos_right') }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-show="chart.type && !chart.type.includes('table')" :label="$t('chart.text_v_position')" class="form-item">
|
||||
<el-form-item v-show="chart.type && !chart.type.includes('table') && chart.type !== 'liquid'" :label="$t('chart.text_v_position')" class="form-item">
|
||||
<el-radio-group v-model="titleForm.vPosition" size="mini" @change="changeTitleStyle">
|
||||
<el-radio-button label="top">{{ $t('chart.text_pos_top') }}</el-radio-button>
|
||||
<el-radio-button label="center">{{ $t('chart.text_pos_center') }}</el-radio-button>
|
||||
|
@ -165,6 +165,7 @@
|
||||
</el-form>
|
||||
|
||||
<el-form v-show="chart.type && chart.type === 'chart-mix'" ref="sizeFormBar" :disabled="param && !hasDataPermission('manage',param.privileges)" :model="sizeForm" label-width="80px" size="mini">
|
||||
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_bar') }}</el-divider>
|
||||
<el-form-item :label="$t('chart.adapt')" class="form-item">
|
||||
<el-checkbox v-model="sizeForm.barDefault" @change="changeBarSizeCase">{{ $t('chart.adapt') }}</el-checkbox>
|
||||
</el-form-item>
|
||||
@ -174,7 +175,7 @@
|
||||
<el-form-item :label="$t('chart.bar_gap')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.barGap" :disabled="sizeForm.barDefault" show-input :show-input-controls="false" input-size="mini" :min="0" :max="5" :step="0.1" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-divider />
|
||||
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_line') }}</el-divider>
|
||||
<el-form-item :label="$t('chart.line_width')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.lineWidth" show-input :show-input-controls="false" input-size="mini" :min="0" :max="10" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
@ -203,7 +204,7 @@
|
||||
<el-form-item :label="$t('chart.line_area')" class="form-item">
|
||||
<el-checkbox v-model="sizeForm.lineArea" @change="changeBarSizeCase">{{ $t('chart.show') }}</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-divider />
|
||||
<el-divider content-position="center" class="divider-style">{{ $t('chart.chart_scatter') }}</el-divider>
|
||||
<el-form-item :label="$t('chart.bubble_symbol')" class="form-item">
|
||||
<el-select v-model="sizeForm.scatterSymbol" :placeholder="$t('chart.line_symbol')" @change="changeBarSizeCase">
|
||||
<el-option
|
||||
@ -234,19 +235,19 @@
|
||||
<el-input-number v-model="sizeForm.liquidMax" :min="1" size="mini" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.radar_size')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.liquidSize" show-input :show-input-controls="false" input-size="mini" :min="0" :max="100" @change="changeBarSizeCase" />
|
||||
<el-slider v-model="sizeForm.liquidSize" show-input :show-input-controls="false" input-size="mini" :min="1" :max="100" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.liquid_outline_border')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.liquidOutlineBorder" show-input :show-input-controls="false" input-size="mini" :min="1" :max="20" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.liquid_outline_distance')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.liquidOutlineDistance" show-input :show-input-controls="false" input-size="mini" :min="1" :max="20" @change="changeBarSizeCase" />
|
||||
<el-slider v-model="sizeForm.liquidOutlineDistance" show-input :show-input-controls="false" input-size="mini" :min="0" :max="20" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.liquid_wave_length')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.liquidWaveLength" show-input :show-input-controls="false" input-size="mini" :min="1" :max="500" @change="changeBarSizeCase" />
|
||||
<el-slider v-model="sizeForm.liquidWaveLength" show-input :show-input-controls="false" input-size="mini" :min="10" :max="500" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('chart.liquid_wave_count')" class="form-item form-item-slider">
|
||||
<el-slider v-model="sizeForm.liquidWaveCount" show-input :show-input-controls="false" input-size="mini" :min="1" :max="10" @change="changeBarSizeCase" />
|
||||
<el-slider v-model="sizeForm.liquidWaveCount" show-input :show-input-controls="false" input-size="mini" :min="2" :max="10" @change="changeBarSizeCase" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
@ -322,7 +323,7 @@ export default {
|
||||
this.sizeForm.liquidMax = this.sizeForm.liquidMax ? this.sizeForm.liquidMax : DEFAULT_SIZE.liquidMax
|
||||
this.sizeForm.liquidSize = this.sizeForm.liquidSize ? this.sizeForm.liquidSize : DEFAULT_SIZE.liquidSize
|
||||
this.sizeForm.liquidOutlineBorder = this.sizeForm.liquidOutlineBorder ? this.sizeForm.liquidOutlineBorder : DEFAULT_SIZE.liquidOutlineBorder
|
||||
this.sizeForm.liquidOutlineDistance = this.sizeForm.liquidOutlineDistance ? this.sizeForm.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance
|
||||
this.sizeForm.liquidOutlineDistance = (this.sizeForm.liquidOutlineDistance || this.sizeForm.liquidOutlineDistance === 0) ? this.sizeForm.liquidOutlineDistance : DEFAULT_SIZE.liquidOutlineDistance
|
||||
this.sizeForm.liquidWaveLength = this.sizeForm.liquidWaveLength ? this.sizeForm.liquidWaveLength : DEFAULT_SIZE.liquidWaveLength
|
||||
this.sizeForm.liquidWaveCount = this.sizeForm.liquidWaveCount ? this.sizeForm.liquidWaveCount : DEFAULT_SIZE.liquidWaveCount
|
||||
}
|
||||
@ -372,4 +373,10 @@ export default {
|
||||
.el-divider--horizontal {
|
||||
margin: 10px 0
|
||||
}
|
||||
.divider-style>>>.el-divider__text{
|
||||
color: #606266;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
padding: 0 10px;
|
||||
}
|
||||
</style>
|
||||
|
@ -503,7 +503,7 @@
|
||||
<el-collapse-item v-show="view.type && view.type.includes('radar')" name="split" :title="$t('chart.split')">
|
||||
<split-selector :param="param" class="attr-selector" :chart="chart" @onChangeSplitForm="onChangeSplitForm" />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item v-show="view.type && view.type !== 'liquid'" name="title" :title="$t('chart.title')">
|
||||
<el-collapse-item v-show="view.type" name="title" :title="$t('chart.title')">
|
||||
<title-selector :param="param" class="attr-selector" :chart="chart" @onTextChange="onTextChange" />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item v-show="view.type && view.type !== 'map' && !view.type.includes('table') && !view.type.includes('text') && chart.type !== 'treemap' && view.type !== 'liquid'" name="legend" :title="$t('chart.legend')">
|
||||
|
@ -15,11 +15,11 @@
|
||||
{{ $t('login.welcome') + (uiInfo && uiInfo['ui.title'] && uiInfo['ui.title'].paramValue || ' DataEase') }}
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<el-form-item v-if="openLdap">
|
||||
<el-radio-group v-if="openLdap" v-model="loginForm.loginType">
|
||||
<el-radio v-if="openLdap" :label="0" size="mini">普通登录</el-radio>
|
||||
<el-radio v-if="openLdap" :label="1" size="mini">LDAP</el-radio>
|
||||
|
||||
<el-form-item v-if="loginTypes.length > 1">
|
||||
<el-radio-group v-if="loginTypes.length > 1" v-model="loginForm.loginType" @change="changeLoginType">
|
||||
<el-radio :label="0" size="mini">普通登录</el-radio>
|
||||
<el-radio v-if="loginTypes.includes(1)" :label="1" size="mini">LDAP</el-radio>
|
||||
<el-radio v-if="loginTypes.includes(2)" :label="2" size="mini">OIDC</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
@ -56,41 +56,20 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<plugin-com v-if="loginTypes.includes(2) && loginForm.loginType === 2" ref="SSOComponent" component-name="SSOComponent" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { encrypt } from '@/utils/rsaEncrypt'
|
||||
import { ldapStatus } from '@/api/user'
|
||||
import { ldapStatus, oidcStatus } from '@/api/user'
|
||||
import { getSysUI } from '@/utils/auth'
|
||||
import PluginCom from '@/views/system/plugin/PluginCom'
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: { PluginCom },
|
||||
data() {
|
||||
// const validateUsername = (rule, value, callback) => {
|
||||
// const userName = value.trim()
|
||||
// validateUserName({ userName: userName }).then(res => {
|
||||
// if (res.data) {
|
||||
// callback()
|
||||
// } else {
|
||||
// callback(this.$t('login.username_error'))
|
||||
// }
|
||||
// }).catch(() => {
|
||||
// callback(this.$t('login.username_error'))
|
||||
// })
|
||||
// // if (!validUsername(value)) {
|
||||
// // callback(new Error('Please enter the correct user name'))
|
||||
// // } else {
|
||||
// // callback()
|
||||
// // }
|
||||
// }
|
||||
// const validatePassword = (rule, value, callback) => {
|
||||
// if (value.length < 8) {
|
||||
// callback(this.$t('login.password_error'))
|
||||
// } else {
|
||||
// callback()
|
||||
// }
|
||||
// }
|
||||
return {
|
||||
loginForm: {
|
||||
loginType: 0,
|
||||
@ -108,7 +87,7 @@ export default {
|
||||
loginImageUrl: null,
|
||||
loginLogoUrl: null,
|
||||
axiosFinished: false,
|
||||
openLdap: true
|
||||
loginTypes: [0]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -126,7 +105,15 @@ export default {
|
||||
},
|
||||
beforeCreate() {
|
||||
ldapStatus().then(res => {
|
||||
this.openLdap = res.success && res.data
|
||||
if (res.success && res.data) {
|
||||
this.loginTypes.push(1)
|
||||
}
|
||||
})
|
||||
|
||||
oidcStatus().then(res => {
|
||||
if (res.success && res.data) {
|
||||
this.loginTypes.push(2)
|
||||
}
|
||||
})
|
||||
},
|
||||
created() {
|
||||
@ -169,6 +156,12 @@ export default {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
changeLoginType(val) {
|
||||
if (val !== 2) return
|
||||
this.$nextTick(() => {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,41 @@
|
||||
<template xmlns:el-col="http://www.w3.org/1999/html">
|
||||
<el-col style="padding: 0 5px 0 5px;">
|
||||
<el-col>
|
||||
<el-row style="margin-bottom: 10px">
|
||||
<el-col :span="16">
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
size="mini"
|
||||
:placeholder="$t('commons.search')"
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
/>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-dropdown>
|
||||
<el-button size="mini" type="primary">
|
||||
{{ searchMap[searchType] }}<i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item @click.native="searchTypeClick('all')">全部</el-dropdown-item>
|
||||
<el-dropdown-item @click.native="searchTypeClick('folder')">目录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
<!-- <el-select-->
|
||||
<!-- v-model="searchType"-->
|
||||
<!-- default-first-option-->
|
||||
<!-- size="mini"-->
|
||||
<!-- >-->
|
||||
<!-- <el-option-->
|
||||
<!-- v-for="item in searchTypeList"-->
|
||||
<!-- :key="item.value"-->
|
||||
<!-- :label="item.label"-->
|
||||
<!-- :value="item.value"-->
|
||||
<!-- />-->
|
||||
<!-- </el-select>-->
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<span class="header-title">{{ $t('panel.default_panel') }}</span>
|
||||
<div class="block">
|
||||
@ -11,6 +46,7 @@
|
||||
node-key="id"
|
||||
:highlight-current="activeTree==='system'"
|
||||
:expand-on-click-node="true"
|
||||
:filter-node-method="filterNode"
|
||||
@node-click="nodeClick"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node father">
|
||||
@ -59,6 +95,7 @@
|
||||
node-key="id"
|
||||
:highlight-current="activeTree==='self'"
|
||||
:expand-on-click-node="true"
|
||||
:filter-node-method="filterNode"
|
||||
@node-click="nodeClick"
|
||||
>
|
||||
<span slot-scope="{ node, data }" class="custom-tree-node-list father">
|
||||
@ -294,7 +331,14 @@ export default {
|
||||
moveDialogTitle: '',
|
||||
moveInfo: {},
|
||||
tGroup: {},
|
||||
tGroupData: [] // 所有目录
|
||||
tGroupData: [], // 所有目录
|
||||
searchPids: [], // 查询命中的pid
|
||||
filterText: '',
|
||||
searchType: 'all',
|
||||
searchMap: {
|
||||
all: this.$t('commons.all'),
|
||||
folder: this.$t('commons.folder')
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -311,6 +355,16 @@ export default {
|
||||
if (newVal === 'PanelMain' && this.lastActiveNode && this.lastActiveNodeData) {
|
||||
this.activeNodeAndClickOnly(this.lastActiveNodeData)
|
||||
}
|
||||
},
|
||||
filterText(val) {
|
||||
this.searchPids = []
|
||||
this.$refs.default_panel_tree.filter(val)
|
||||
this.$refs.panel_list_tree.filter(val)
|
||||
},
|
||||
searchType(val) {
|
||||
this.searchPids = []
|
||||
this.$refs.default_panel_tree.filter(this.filterText)
|
||||
this.$refs.panel_list_tree.filter(this.filterText)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -710,6 +764,27 @@ export default {
|
||||
targetGroup(val) {
|
||||
this.tGroup = val
|
||||
this.groupMoveConfirmDisabled = false
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
if (this.searchType === 'folder') {
|
||||
if (data.nodeType === 'folder' && data.label.indexOf(value) !== -1) {
|
||||
this.searchPids.push(data.id)
|
||||
return true
|
||||
}
|
||||
if (this.searchPids.indexOf(data.pid) !== -1) {
|
||||
if (data.nodeType === 'folder') {
|
||||
this.searchPids.push(data.id)
|
||||
}
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return data.label.indexOf(value) !== -1
|
||||
}
|
||||
return false
|
||||
},
|
||||
searchTypeClick(searchTypeInfo) {
|
||||
this.searchType = searchTypeInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
69
frontend/src/views/system/plugin/PluginCom.vue
Normal file
69
frontend/src/views/system/plugin/PluginCom.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div>
|
||||
<async-component v-if="showAsync" :url="url" @execute-axios="executeAxios" @on-add-languanges="addLanguages" @plugin-call-back="pluginCallBack" />
|
||||
<div v-else>
|
||||
<h1>未知组件无法展示</h1>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AsyncComponent from '@/components/AsyncComponent'
|
||||
import i18n from '@/lang'
|
||||
import bus from '@/utils/bus'
|
||||
import { execute } from '@/api/system/dynamic'
|
||||
export default {
|
||||
name: 'PluginCom',
|
||||
components: {
|
||||
AsyncComponent
|
||||
},
|
||||
props: {
|
||||
componentName: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showAsync: false,
|
||||
baseUrl: '/api/pluginCommon/component/',
|
||||
url: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.componentName) {
|
||||
this.showAsync = true
|
||||
this.url = this.baseUrl + this.componentName
|
||||
} else {
|
||||
this.showAsync = false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// hasLicense
|
||||
executeAxios(options) {
|
||||
execute(options).then(res => {
|
||||
if (options.callBack) {
|
||||
options.callBack(res)
|
||||
}
|
||||
}).catch(e => {
|
||||
if (options.callBack) {
|
||||
options.callBack(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
addLanguages(options) {
|
||||
for (const key in i18n.messages) {
|
||||
if (Object.hasOwnProperty.call(i18n.messages, key)) {
|
||||
const element = options[key]
|
||||
i18n.mergeLocaleMessage(key, element)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
pluginCallBack(param) {
|
||||
const { eventName, eventParam } = param
|
||||
bus.$emit(eventName, eventParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -22,7 +22,7 @@
|
||||
<!-- <el-table-column prop="gender" :label="$t('commons.gender')" width="60" /> -->
|
||||
<el-table-column prop="from" :label="$t('user.source')" width="80">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.from === 0 ? 'LOCAL' : 'LDAP' }}</div>
|
||||
<div>{{ scope.row.from === 0 ? 'LOCAL' : scope.row.from === 1 ? 'LDAP' : 'OIDC' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user