diff --git a/backend/pom.xml b/backend/pom.xml
index 0b94144982..360ed3f072 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -18,6 +18,9 @@
1.8
20.1.0
3.12.1
+
+ 4.0.0
+ 3.3.0
@@ -36,12 +39,7 @@
org.springframework.boot
spring-boot-starter-web
-
+
@@ -89,11 +87,7 @@
lombok
-
+
org.springframework.boot
@@ -122,7 +116,7 @@
org.apache.shiro
- shiro-spring-boot-starter
+ shiro-spring
${shiro.version}
@@ -236,8 +230,7 @@
-
+
io.dataease
dataease-plugin-interface
@@ -336,6 +329,7 @@
org.apache.commons
commons-pool2
+
@@ -350,9 +344,7 @@
src/main/resources
-
+
true
static/**/*.woff
diff --git a/backend/src/main/java/io/dataease/auth/api/AuthApi.java b/backend/src/main/java/io/dataease/auth/api/AuthApi.java
index c7219799a7..51080b57b0 100644
--- a/backend/src/main/java/io/dataease/auth/api/AuthApi.java
+++ b/backend/src/main/java/io/dataease/auth/api/AuthApi.java
@@ -38,6 +38,10 @@ public interface AuthApi {
@PostMapping("/logout")
String logout();
+ @ApiIgnore
+ @PostMapping("/deLogout")
+ String deLogout();
+
@ApiOperation("验证账号")
@PostMapping("/validateName")
Boolean validateName(Map nameDto);
@@ -50,6 +54,10 @@ public interface AuthApi {
@PostMapping("/isOpenOidc")
boolean isOpenOidc();
+ @ApiOperation("是否开启cas")
+ @PostMapping("/isOpenCas")
+ boolean isOpenCas();
+
@ApiIgnore
@PostMapping("/isPluginLoaded")
boolean isPluginLoaded();
diff --git a/backend/src/main/java/io/dataease/auth/config/cas/CasStrategy.java b/backend/src/main/java/io/dataease/auth/config/cas/CasStrategy.java
new file mode 100644
index 0000000000..7a8693b428
--- /dev/null
+++ b/backend/src/main/java/io/dataease/auth/config/cas/CasStrategy.java
@@ -0,0 +1,60 @@
+package io.dataease.auth.config.cas;
+
+import io.dataease.auth.service.impl.ShiroServiceImpl;
+import io.dataease.commons.utils.CommonBeanFactory;
+import io.dataease.service.system.SystemParameterService;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.util.AntPathMatcher;
+import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+@Component
+public class CasStrategy implements UrlPatternMatcherStrategy {
+
+
+ private static Set releaseTypes = new HashSet<>();
+
+ @PostConstruct
+ public void init() {
+ releaseTypes.add("anon");
+ releaseTypes.add("link");
+ releaseTypes.add("doc");
+ }
+ @Override
+ public boolean matches(String s) {
+ SystemParameterService service = CommonBeanFactory.getBean(SystemParameterService.class);
+ String serviceValue = service.getValue("cas.callBack");
+ if (StringUtils.isBlank(serviceValue)) return false;
+ String serverName = serviceValue.substring(0, serviceValue.indexOf("/cas/callBack"));
+ int beginIndex = -1;
+ if ((beginIndex = s.indexOf(serverName)) != -1) {
+ s = s.substring(beginIndex + serverName.length());
+ }
+ if (StringUtils.equals("/", s)) return false;
+ if (StringUtils.equals("/login", s)) return false;
+ if (StringUtils.startsWith(s, "/cas/callBack")) return false;
+ if (StringUtils.equals("/api/auth/deLogout", s)) return true;
+ AntPathMatcher antPathMatcher = new AntPathMatcher();
+ ShiroServiceImpl shiroService = CommonBeanFactory.getBean(ShiroServiceImpl.class);
+ Map stringStringMap = shiroService.loadFilterChainDefinitionMap();
+ for (Map.Entry entry : stringStringMap.entrySet()) {
+ if (releaseTypes.contains(entry.getValue())) {
+ boolean matches = antPathMatcher.matches(entry.getKey(), s);
+ if (matches) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setPattern(String s) {
+
+ }
+}
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 42a685d42a..eee98e7ca0 100644
--- a/backend/src/main/java/io/dataease/auth/server/AuthServer.java
+++ b/backend/src/main/java/io/dataease/auth/server/AuthServer.java
@@ -17,12 +17,14 @@ import io.dataease.i18n.Translator;
import io.dataease.plugins.common.entity.XpackLdapUserEntity;
import io.dataease.plugins.config.SpringContextUtil;
import io.dataease.plugins.util.PluginUtils;
+import io.dataease.plugins.xpack.cas.service.CasXpackService;
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 io.dataease.service.sys.SysUserService;
+import io.dataease.service.system.SystemParameterService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
@@ -36,7 +38,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
@RestController
public class AuthServer implements AuthApi {
@@ -50,6 +54,9 @@ public class AuthServer implements AuthApi {
@Autowired
private SysUserService sysUserService;
+ @Resource
+ private SystemParameterService systemParameterService;
+
@Override
public Object login(@RequestBody LoginDto loginDto) throws Exception {
String username = RsaUtil.decryptByPrivateKey(RsaProperties.privateKey, loginDto.getUsername());
@@ -159,6 +166,37 @@ public class AuthServer implements AuthApi {
return DEFAULT_PWD;
}
+ @Override
+ public String deLogout() {
+ String token = ServletUtils.getToken();
+ if (StringUtils.isEmpty(token) || StringUtils.equals("null", token) || StringUtils.equals("undefined", token)) {
+ return "success";
+ }
+ SecurityUtils.getSubject().logout();
+ String result = null;
+ Integer defaultLoginType = systemParameterService.defaultLoginType();
+ if (defaultLoginType == 3 && isOpenCas()) {
+ HttpServletRequest request = ServletUtils.request();
+ HttpSession session = request.getSession();
+ session.invalidate();
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ result = casXpackService.logout();
+ }
+ try {
+ Long userId = JWTUtils.tokenInfoByToken(token).getUserId();
+ authUserService.clearCache(userId);
+ if (StringUtils.isBlank(result)) {
+ result = "success";
+ }
+ } catch (Exception e) {
+ LogUtil.error(e);
+ if (StringUtils.isBlank(result)) {
+ result = "fail";
+ }
+ }
+ return result;
+ }
+
@Override
public String logout() {
String token = ServletUtils.getToken();
@@ -170,20 +208,36 @@ public class AuthServer implements AuthApi {
OidcXpackService oidcXpackService = SpringContextUtil.getBean(OidcXpackService.class);
oidcXpackService.logout(idToken);
}
-
}
+
if (StringUtils.isEmpty(token) || StringUtils.equals("null", token) || StringUtils.equals("undefined", token)) {
return "success";
}
+
+ SecurityUtils.getSubject().logout();
+ String result = null;
+ Integer defaultLoginType = systemParameterService.defaultLoginType();
+ if (defaultLoginType == 3 && isOpenCas()) {
+ HttpServletRequest request = ServletUtils.request();
+ HttpSession session = request.getSession();
+ session.invalidate();
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ result = casXpackService.logout();
+ }
try {
Long userId = JWTUtils.tokenInfoByToken(token).getUserId();
+
authUserService.clearCache(userId);
+ if (StringUtils.isBlank(result)) {
+ result = "success";
+ }
} catch (Exception e) {
LogUtil.error(e);
- return "fail";
+ if (StringUtils.isBlank(result)) {
+ result = "fail";
+ }
}
-
- return "success";
+ return result;
}
@Override
@@ -211,6 +265,17 @@ public class AuthServer implements AuthApi {
return authUserService.supportOidc();
}
+
+ @Override
+ public boolean isOpenCas() {
+ Boolean licValid = PluginUtils.licValid();
+ if (!licValid)
+ return false;
+ Boolean supportCas = authUserService.supportCas();
+
+ return authUserService.supportCas();
+ }
+
@Override
public boolean isPluginLoaded() {
Boolean licValid = PluginUtils.licValid();
diff --git a/backend/src/main/java/io/dataease/auth/service/AuthUserService.java b/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
index c9e4bc60bb..41fdd96632 100644
--- a/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
+++ b/backend/src/main/java/io/dataease/auth/service/AuthUserService.java
@@ -14,6 +14,8 @@ public interface AuthUserService {
SysUserEntity getLdapUserByName(String username);
+ SysUserEntity getCasUserByName(String username);
+
SysUserEntity getUserBySub(String sub);
List roles(Long userId);
@@ -28,6 +30,8 @@ public interface AuthUserService {
Boolean supportOidc();
+ Boolean supportCas();
+
Boolean pluginLoaded();
diff --git a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
index e01fd35ba4..e83030deab 100644
--- a/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
+++ b/backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
@@ -10,6 +10,7 @@ import io.dataease.plugins.common.base.domain.SysUser;
import io.dataease.plugins.common.base.mapper.SysUserMapper;
import io.dataease.plugins.common.service.PluginCommonService;
import io.dataease.plugins.config.SpringContextUtil;
+import io.dataease.plugins.xpack.cas.service.CasXpackService;
import io.dataease.plugins.xpack.ldap.service.LdapXpackService;
import io.dataease.plugins.xpack.oidc.service.OidcXpackService;
@@ -65,6 +66,11 @@ public class AuthUserServiceImpl implements AuthUserService {
return authMapper.findLdapUserByName(username);
}
+ @Override
+ public SysUserEntity getCasUserByName(String username) {
+ return authMapper.findCasUserByName(username);
+ }
+
@Override
public SysUserEntity getUserBySub(String sub) {
return authMapper.findUserBySub(sub);
@@ -147,6 +153,15 @@ public class AuthUserServiceImpl implements AuthUserService {
return oidcXpackService.isSuuportOIDC();
}
+ @Override
+ public Boolean supportCas() {
+ Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((CasXpackService.class));
+ if (beansOfType.keySet().size() == 0) return false;
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ if (ObjectUtils.isEmpty(casXpackService)) return false;
+ return casXpackService.suuportCas();
+ }
+
@Override
public Boolean pluginLoaded() {
Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((PluginCommonService.class));
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 6d226ef715..168ed90719 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
@@ -84,6 +84,8 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/api/pluginCommon/staticInfo/**", ANON);
filterChainDefinitionMap.put("/plugin/oidc/authInfo", ANON);
filterChainDefinitionMap.put("/sso/callBack*", ANON);
+ filterChainDefinitionMap.put("/cas/callBack*", ANON);
+ filterChainDefinitionMap.put("/cas/reset", ANON);
filterChainDefinitionMap.put("/unauth", ANON);
filterChainDefinitionMap.put("/display/**", ANON);
@@ -91,7 +93,6 @@ public class ShiroServiceImpl implements ShiroService {
filterChainDefinitionMap.put("/downline", ANON);
filterChainDefinitionMap.put("/common-files/**", ANON);
filterChainDefinitionMap.put("/linkage/getPanelAllLinkageInfo/**", ANON);
- filterChainDefinitionMap.put("/api/auth/logout", "logout");
filterChainDefinitionMap.put("/api/link/resourceDetail/**", "link");
filterChainDefinitionMap.put("/api/link/viewDetail/**", "link");
diff --git a/backend/src/main/java/io/dataease/commons/filter/SqlFilter.java b/backend/src/main/java/io/dataease/commons/filter/SqlFilter.java
index 1c29391c09..6439f27b8e 100644
--- a/backend/src/main/java/io/dataease/commons/filter/SqlFilter.java
+++ b/backend/src/main/java/io/dataease/commons/filter/SqlFilter.java
@@ -3,7 +3,10 @@ package io.dataease.commons.filter;
import io.dataease.commons.exception.DEException;
import io.dataease.commons.holder.ThreadLocalContextHolder;
import io.dataease.commons.wrapper.XssAndSqlHttpServletRequestWrapper;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
@@ -20,7 +23,10 @@ public class SqlFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
-
+ if (ObjectUtils.isEmpty(RequestContextHolder.getRequestAttributes())) {
+ ServletRequestAttributes attributes = new ServletRequestAttributes((HttpServletRequest) request);
+ RequestContextHolder.setRequestAttributes(attributes);
+ }
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if ("TRACE".equalsIgnoreCase(httpRequest.getMethod()) || "TRACK".equalsIgnoreCase(httpRequest.getMethod())) {
diff --git a/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java b/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java
index f00673a3ce..456bab17b7 100644
--- a/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java
+++ b/backend/src/main/java/io/dataease/controller/sys/SystemParameterController.java
@@ -7,6 +7,7 @@ import io.dataease.controller.sys.response.MailInfo;
import io.dataease.dto.SystemParameterDTO;
import io.dataease.listener.DatasetCheckListener;
import io.dataease.listener.util.CacheUtils;
+import io.dataease.plugins.xpack.cas.dto.CasSaveResult;
import io.dataease.service.FileService;
import io.dataease.service.system.EmailService;
import io.dataease.service.system.SystemParameterService;
@@ -66,14 +67,14 @@ public class SystemParameterController {
@RequiresPermissions("sysparam:read")
@PostMapping("/edit/basic")
- public void editBasic(@RequestBody List systemParameter) {
+ public CasSaveResult editBasic(@RequestBody List systemParameter) {
int timeout = Integer.parseInt(systemParameter.stream().filter(
parameter -> parameter.getParamKey().equals("basic.frontTimeOut")
).findFirst().get().getParamValue());
if (timeout < 0 || timeout > 300) { //增加了合法性检验
throw new NumberFormatException("Timeout Range Error!");
}
- systemParameterService.editBasic(systemParameter);
+ return systemParameterService.editBasic(systemParameter);
}
@PostMapping("/testConnection")
diff --git a/backend/src/main/java/io/dataease/ext/AuthMapper.java b/backend/src/main/java/io/dataease/ext/AuthMapper.java
index 62557fbc57..8824240ab1 100644
--- a/backend/src/main/java/io/dataease/ext/AuthMapper.java
+++ b/backend/src/main/java/io/dataease/ext/AuthMapper.java
@@ -27,6 +27,8 @@ public interface AuthMapper {
SysUserEntity findLdapUserByName(@Param("username") String username);
+ SysUserEntity findCasUserByName(@Param("username") String username);
+
SysUserEntity findUserBySub(@Param("sub") String sub);
diff --git a/backend/src/main/java/io/dataease/ext/AuthMapper.xml b/backend/src/main/java/io/dataease/ext/AuthMapper.xml
index 24b66c869c..4322d3469b 100644
--- a/backend/src/main/java/io/dataease/ext/AuthMapper.xml
+++ b/backend/src/main/java/io/dataease/ext/AuthMapper.xml
@@ -49,6 +49,11 @@
select user_id, username,nick_name, dept_id, password, enabled,email, phone, language ,is_admin, `from` from sys_user a where username = #{username} and a.from = 1
+
+
+
diff --git a/backend/src/main/java/io/dataease/listener/CasStatusListener.java b/backend/src/main/java/io/dataease/listener/CasStatusListener.java
new file mode 100644
index 0000000000..aa4c1abcd1
--- /dev/null
+++ b/backend/src/main/java/io/dataease/listener/CasStatusListener.java
@@ -0,0 +1,27 @@
+package io.dataease.listener;
+
+import io.dataease.plugins.config.SpringContextUtil;
+import io.dataease.plugins.xpack.cas.service.CasXpackService;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletContext;
+import java.util.Map;
+
+@Component
+public class CasStatusListener implements ApplicationListener {
+
+
+
+ @Override
+ public void onApplicationEvent(ApplicationReadyEvent event) {
+ Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((CasXpackService.class));
+ if (beansOfType.keySet().size() == 0) return;
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ if (ObjectUtils.isEmpty(casXpackService)) return;
+ ServletContext servletContext = event.getApplicationContext().getBean(ServletContext.class);
+ casXpackService.checkCasStatus(servletContext);
+ }
+}
diff --git a/backend/src/main/java/io/dataease/plugins/server/CasServer.java b/backend/src/main/java/io/dataease/plugins/server/CasServer.java
new file mode 100644
index 0000000000..d342cbcb55
--- /dev/null
+++ b/backend/src/main/java/io/dataease/plugins/server/CasServer.java
@@ -0,0 +1,103 @@
+package io.dataease.plugins.server;
+
+import cn.hutool.core.util.RandomUtil;
+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.utils.CodingUtil;
+import io.dataease.commons.utils.LogUtil;
+import io.dataease.commons.utils.ServletUtils;
+
+import io.dataease.service.sys.SysUserService;
+import io.dataease.service.system.SystemParameterService;
+import org.apache.commons.lang3.StringUtils;
+import org.jasig.cas.client.authentication.AttributePrincipal;
+import org.jasig.cas.client.util.AssertionHolder;
+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.ResponseBody;
+import org.springframework.web.servlet.ModelAndView;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.annotation.Resource;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+@ApiIgnore
+@RequestMapping("/cas")
+@Controller
+public class CasServer {
+
+ @Autowired
+ private AuthUserService authUserService;
+
+ @Autowired
+ private SysUserService sysUserService;
+
+ @Resource
+ private SystemParameterService systemParameterService;
+
+ @GetMapping("/callBack")
+ public ModelAndView callBack() {
+ ModelAndView modelAndView = new ModelAndView("redirect:/");
+ HttpServletResponse response = ServletUtils.response();
+
+ AttributePrincipal principal = AssertionHolder.getAssertion().getPrincipal();
+ String name = principal.getName();
+ try {
+ SysUserEntity sysUserEntity = authUserService.getCasUserByName(name);
+ if(null == sysUserEntity){
+ String s = RandomUtil.randomString(6);
+ String email = s + "@xxx.com";
+ sysUserService.validateCasUser(name);
+ sysUserService.saveCASUser(name, email);
+ sysUserEntity = authUserService.getUserByName(name);
+ }
+ String realPwd = CodingUtil.md5(sysUserService.defaultPWD());
+ TokenInfo tokenInfo = TokenInfo.builder().userId(sysUserEntity.getUserId()).username(sysUserEntity.getUsername()).build();
+ String token = JWTUtils.sign(tokenInfo, realPwd);
+ ServletUtils.setToken(token);
+ Cookie cookie_token = new Cookie("Authorization", token);cookie_token.setPath("/");
+ response.addCookie(cookie_token);
+
+ }catch(Exception e) {
+
+ String msg = e.getMessage();
+ if (null != e.getCause()) {
+ msg = e.getCause().getMessage();
+ }
+ try {
+ msg = URLEncoder.encode(msg, "UTF-8");
+ LogUtil.error(e);
+ Cookie cookie_error = new Cookie("CasError", msg);
+ cookie_error.setPath("/");
+ response.addCookie(cookie_error);
+
+ return modelAndView;
+ } catch (UnsupportedEncodingException e1) {
+ e.printStackTrace();
+ }
+ }
+ return modelAndView;
+ }
+
+ @GetMapping("/reset")
+ @ResponseBody
+ public String reset() {
+ systemParameterService.resetCas();
+ String token = ServletUtils.getToken();
+ if (StringUtils.isNotBlank(token)) {
+ Long userId = JWTUtils.tokenInfoByToken(token).getUserId();
+ authUserService.clearCache(userId);
+ }
+ HttpServletRequest request = ServletUtils.request();
+ request.getSession().invalidate();
+ return "已经切换默认登录方式";
+ }
+}
diff --git a/backend/src/main/java/io/dataease/plugins/server/XCasServer.java b/backend/src/main/java/io/dataease/plugins/server/XCasServer.java
new file mode 100644
index 0000000000..a41476e0ce
--- /dev/null
+++ b/backend/src/main/java/io/dataease/plugins/server/XCasServer.java
@@ -0,0 +1,35 @@
+package io.dataease.plugins.server;
+
+
+import io.dataease.plugins.config.SpringContextUtil;
+import io.dataease.plugins.xpack.cas.dto.CasSaveResult;
+import io.dataease.plugins.xpack.cas.service.CasXpackService;
+import io.dataease.plugins.xpack.display.dto.response.SysSettingDto;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.List;
+
+@ApiIgnore
+@RequestMapping("/plugin/cas")
+@RestController
+public class XCasServer {
+
+
+ @PostMapping("/info")
+ public List getOidcInfo() {
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ return casXpackService.casSettings();
+ }
+
+ @RequiresPermissions("sysparam:read")
+ @PostMapping("/save")
+ public CasSaveResult save(@RequestBody List settings) {
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ return casXpackService.save(settings);
+ }
+}
diff --git a/backend/src/main/java/io/dataease/service/sys/SysUserService.java b/backend/src/main/java/io/dataease/service/sys/SysUserService.java
index 20a8ac5fd2..5fc90e9ec8 100644
--- a/backend/src/main/java/io/dataease/service/sys/SysUserService.java
+++ b/backend/src/main/java/io/dataease/service/sys/SysUserService.java
@@ -124,6 +124,31 @@ public class SysUserService {
}
}
+ @Transactional
+ public void saveCASUser(String name, String email) {
+ long now = System.currentTimeMillis();
+ SysUser sysUser = new SysUser();
+ sysUser.setUsername(name);
+ sysUser.setNickName(name);
+ sysUser.setEmail(email);
+ sysUser.setPassword(CodingUtil.md5(DEFAULT_PWD));
+ sysUser.setCreateTime(now);
+ sysUser.setUpdateTime(now);
+ sysUser.setEnabled(1L);
+ sysUser.setLanguage("zh_CN");
+ sysUser.setFrom(3);
+ sysUser.setIsAdmin(false);
+ // sysUser.setSub(ssoUserInfo.getSub());
+ sysUserMapper.insert(sysUser);
+ SysUser dbUser = findOne(sysUser);
+ if (null != dbUser && null != dbUser.getUserId()) {
+ // oidc默认角色是普通员工
+ List roleIds = new ArrayList();
+ roleIds.add(2L);
+ saveUserRoles( dbUser.getUserId(), roleIds);
+ }
+ }
+
public String defaultPWD() {
return DEFAULT_PWD;
}
@@ -323,6 +348,14 @@ public class SysUserService {
return null;
}
+ public void validateCasUser(String userName) {
+ SysUserExample example = new SysUserExample();
+ example.createCriteria().andUsernameEqualTo(userName);
+ List users = sysUserMapper.selectByExample(example);
+ if(CollectionUtils.isNotEmpty(users)) {
+ throw new RuntimeException("用户ID【"+userName+"】已存在,请联系管理员");
+ }
+ }
public void validateExistUser(String userName, String nickName, String email) {
SysUserExample example = new SysUserExample();
if (StringUtils.isNotBlank(userName)) {
diff --git a/backend/src/main/java/io/dataease/service/system/SystemParameterService.java b/backend/src/main/java/io/dataease/service/system/SystemParameterService.java
index 098d3b0dae..1a85f3046b 100644
--- a/backend/src/main/java/io/dataease/service/system/SystemParameterService.java
+++ b/backend/src/main/java/io/dataease/service/system/SystemParameterService.java
@@ -10,8 +10,12 @@ import io.dataease.plugins.common.base.domain.FileMetadata;
import io.dataease.plugins.common.base.domain.SystemParameter;
import io.dataease.plugins.common.base.domain.SystemParameterExample;
import io.dataease.plugins.common.base.mapper.SystemParameterMapper;
+import io.dataease.plugins.config.SpringContextUtil;
+import io.dataease.plugins.xpack.cas.dto.CasSaveResult;
+import io.dataease.plugins.xpack.cas.service.CasXpackService;
import io.dataease.service.FileService;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -22,6 +26,8 @@ import javax.imageio.ImageIO;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+
import io.dataease.ext.*;
@Service
@@ -29,6 +35,7 @@ import io.dataease.ext.*;
public class SystemParameterService {
private final static String LOGIN_TYPE_KEY = "basic.loginType";
+ private final static String CAS_LOGIN_TYPE = "3";
@Resource
private SystemParameterMapper systemParameterMapper;
@Resource
@@ -81,8 +88,11 @@ public class SystemParameterService {
return result;
}
- public void editBasic(List parameters) {
- parameters.forEach(parameter -> {
+ @Transactional
+ public CasSaveResult editBasic(List parameters) {
+ CasSaveResult casSaveResult = afterSwitchDefaultLogin(parameters);
+ for (int i = 0; i < parameters.size(); i++) {
+ SystemParameter parameter = parameters.get(i);
SystemParameterExample example = new SystemParameterExample();
example.createCriteria().andParamKeyEqualTo(parameter.getParamKey());
@@ -92,8 +102,65 @@ public class SystemParameterService {
systemParameterMapper.insert(parameter);
}
example.clear();
+ }
+ return casSaveResult;
+ }
+ @Transactional
+ public void resetCas() {
+ Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((CasXpackService.class));
+ if (beansOfType.keySet().size() == 0) DEException.throwException("当前未启用CAS");
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ if (ObjectUtils.isEmpty(casXpackService)) DEException.throwException("当前未启用CAS");
+
+ String loginTypePk = "basic.loginType";
+ SystemParameter loginTypeParameter = systemParameterMapper.selectByPrimaryKey(loginTypePk);
+ if (ObjectUtils.isNotEmpty(loginTypeParameter) && StringUtils.equals("3", loginTypeParameter.getParamValue())) {
+ loginTypeParameter.setParamValue("0");
+ systemParameterMapper.updateByPrimaryKeySelective(loginTypeParameter);
+ }
+ casXpackService.setEnabled(false);
+ }
+
+ public CasSaveResult afterSwitchDefaultLogin(List parameters) {
+ CasSaveResult casSaveResult = new CasSaveResult();
+ casSaveResult.setNeedLogout(false);
+ Map beansOfType = SpringContextUtil.getApplicationContext().getBeansOfType((CasXpackService.class));
+ if (beansOfType.keySet().size() == 0) return casSaveResult;
+ CasXpackService casXpackService = SpringContextUtil.getBean(CasXpackService.class);
+ if (ObjectUtils.isEmpty(casXpackService)) return casSaveResult;
+
+ AtomicReference loginType = new AtomicReference();
+ boolean containLoginType = parameters.stream().anyMatch(param -> {
+ if (StringUtils.equals(param.getParamKey(), LOGIN_TYPE_KEY)) {
+ loginType.set(param.getParamValue());
+ return true;
+ }
+ return false;
});
+ if (!containLoginType) return casSaveResult;
+
+
+ SystemParameter systemParameter = systemParameterMapper.selectByPrimaryKey(LOGIN_TYPE_KEY);
+ String originVal = null;
+ if (ObjectUtils.isNotEmpty(systemParameter)) {
+ originVal = systemParameter.getParamValue();
+ }
+
+ if (StringUtils.equals(originVal, loginType.get())) return casSaveResult;
+
+ if (StringUtils.equals(CAS_LOGIN_TYPE, loginType.get())) {
+ casSaveResult.setNeedLogout(true);
+ casXpackService.setEnabled(true);
+ casSaveResult.setCasEnable(true);
+ }
+
+ if (StringUtils.equals(CAS_LOGIN_TYPE, originVal)) {
+ casSaveResult.setNeedLogout(true);
+ casXpackService.setEnabled(false);
+ casSaveResult.setCasEnable(false);
+ }
+ return casSaveResult;
}
public List getParamList(String type) {
@@ -102,6 +169,8 @@ public class SystemParameterService {
return systemParameterMapper.selectByExample(example);
}
+
+
public String getVersion() {
return System.getenv("MS_VERSION");
}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index a90f6d32b9..85a8ccf334 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -114,6 +114,13 @@ server.compression.min-response-size=1024
+server.servlet.context-parameters.configurationStrategy=SYSTEM_PROPERTIES
+server.servlet.session.cookie.http-only=true
+server.servlet.session.tracking-modes=cookie
+
+
+
+
diff --git a/frontend/package.json b/frontend/package.json
index eaeb6cace2..efede49d1e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -79,8 +79,10 @@
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-service": "^3.3.1",
+ "add-asset-html-webpack-plugin": "^3.1.3",
"babel-eslint": "10.0.1",
"chalk": "2.4.2",
+ "clean-webpack-plugin": "^1.0.1",
"connect": "3.6.6",
"copy-webpack-plugin": "^4.6.0",
"eslint": "5.15.3",
@@ -95,11 +97,9 @@
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "^0.7.2",
"serve-static": "^1.13.2",
- "add-asset-html-webpack-plugin": "^3.1.3",
- "clean-webpack-plugin": "^1.0.1",
"vue-template-compiler": "2.6.10",
- "webpack-cli": "^3.2.3",
- "vuetify": "^2.6.6"
+ "vuetify": "^2.6.6",
+ "webpack-cli": "^3.2.3"
},
"engines": {
"node": ">=8.9",
diff --git a/frontend/src/api/user.js b/frontend/src/api/user.js
index 36d1c05370..c57748d5d9 100644
--- a/frontend/src/api/user.js
+++ b/frontend/src/api/user.js
@@ -22,6 +22,13 @@ export function logout() {
})
}
+export function deLogout() {
+ return request({
+ url: '/api/auth/deLogout',
+ method: 'post'
+ })
+}
+
export function needModifyPwd() {
return request({
url: '/api/auth/useInitPwd',
@@ -79,6 +86,13 @@ export function oidcStatus() {
})
}
+export function casStatus() {
+ return request({
+ url: '/api/auth/isOpenCas',
+ method: 'post'
+ })
+}
+
export function pluginLoaded() {
return request({
url: '/api/auth/isPluginLoaded',
diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js
index 03385ad3e6..ffe3fbfcbb 100644
--- a/frontend/src/lang/en.js
+++ b/frontend/src/lang/en.js
@@ -471,7 +471,8 @@ export default {
display: 'Display Setting',
ldap: 'LDAP Setting',
oidc: 'OIDC Setting',
- theme: 'Theme Setting'
+ theme: 'Theme Setting',
+ cas: 'CAS Setting'
},
license: {
i18n_no_license_record: 'No License Record',
@@ -657,7 +658,8 @@ export default {
test_recipients: 'Test recipients',
tip: 'Tip: use as test mail recipient only',
engine_mode_setting: 'Engine Setting',
- kettle_setting: 'Kettle Setting'
+ kettle_setting: 'Kettle Setting',
+ cas_selected_warn: 'Selecting CAS will cause you to login again'
},
chart: {
view_reset: 'View Reset',
diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js
index c2af66b461..bb8c4e40f8 100644
--- a/frontend/src/lang/tw.js
+++ b/frontend/src/lang/tw.js
@@ -471,7 +471,8 @@ export default {
display: '顯示設置',
ldap: 'LDAP設置',
oidc: 'OIDC設置',
- theme: '主題設置'
+ theme: '主題設置',
+ cas: 'CAS設置'
},
license: {
i18n_no_license_record: '沒有 License 記錄',
@@ -645,7 +646,7 @@ export default {
login_type: '默認登錄方式',
empty_front: '為空則默認取值10秒',
empty_msg: '為空則默認取值30天',
- front_error: '請填寫0-300正整數', //修改了提示信息
+ front_error: '請填寫0-300正整數', // 修改了提示信息
msg_error: '請填寫1-365正整數',
SMTP_port: 'SMTP端口',
SMTP_account: 'SMTP賬戶',
@@ -659,7 +660,8 @@ export default {
test_recipients: '測試收件人',
tip: '提示:僅用來作爲測試郵件收件人',
engine_mode_setting: '引擎設置',
- kettle_setting: 'Kettle 設置'
+ kettle_setting: 'Kettle 設置',
+ cas_selected_warn: '選擇CAS方式保存後會註銷當前回話,重新登錄'
},
chart: {
view_reset: '视图重置',
diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js
index 66a0864a84..a96eeb4da2 100644
--- a/frontend/src/lang/zh.js
+++ b/frontend/src/lang/zh.js
@@ -472,7 +472,8 @@ export default {
display: '显示设置',
ldap: 'LDAP设置',
oidc: 'OIDC设置',
- theme: '主题设置'
+ theme: '主题设置',
+ cas: 'CAS设置'
},
license: {
i18n_no_license_record: '没有 License 记录',
@@ -660,7 +661,8 @@ export default {
test_recipients: '测试收件人',
tip: '提示:仅用来作为测试邮件收件人',
engine_mode_setting: '引擎设置',
- kettle_setting: 'Kettle 设置'
+ kettle_setting: 'Kettle 设置',
+ cas_selected_warn: '选择CAS方式保存后会注销当前回话,重新登录'
},
chart: {
view_reset: '视图重置',
diff --git a/frontend/src/layout/components/Topbar.vue b/frontend/src/layout/components/Topbar.vue
index 6036f92ab2..cad4ee778c 100644
--- a/frontend/src/layout/components/Topbar.vue
+++ b/frontend/src/layout/components/Topbar.vue
@@ -197,6 +197,9 @@ export default {
bus.$on('set-top-menu-active-info', this.setTopMenuActiveInfo)
bus.$on('set-top-text-info', this.setTopTextInfo)
bus.$on('set-top-text-active-info', this.setTopTextActiveInfo)
+ bus.$on('sys-logout', param => {
+ this.logout(param)
+ })
this.showTips && this.$nextTick(() => {
const drop = this.$refs['my-drop']
drop && drop.show && drop.show()
@@ -300,9 +303,13 @@ export default {
}
return route.children.filter(kid => !kid.hidden).length
},
- async logout() {
- await this.$store.dispatch('user/logout')
- this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+ async logout(param) {
+ const result = await this.$store.dispatch('user/logout', param)
+ if (result !== 'success' && result !== 'fail') {
+ window.location.href = result
+ } else {
+ this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+ }
},
loadUiInfo() {
this.$store.dispatch('user/getUI').then(() => {
diff --git a/frontend/src/settings.js b/frontend/src/settings.js
index 10faf444f4..2a4f98b21d 100644
--- a/frontend/src/settings.js
+++ b/frontend/src/settings.js
@@ -6,6 +6,7 @@ module.exports = {
/* for sso */
IdTokenKey: 'IdToken',
AccessTokenKey: 'AccessToken',
+ CASSESSION: 'JSESSIONID',
/**
* @type {boolean} true | false
diff --git a/frontend/src/store/modules/user.js b/frontend/src/store/modules/user.js
index e9c43e7774..4ba90dae2f 100644
--- a/frontend/src/store/modules/user.js
+++ b/frontend/src/store/modules/user.js
@@ -1,4 +1,4 @@
-import { login, logout, getInfo, getUIinfo, languageApi } from '@/api/user'
+import { login, logout, deLogout, getInfo, getUIinfo, languageApi } from '@/api/user'
import { getToken, setToken, removeToken, setSysUI } from '@/utils/auth'
import { resetRouter } from '@/router'
import { format } from '@/utils/formatUi'
@@ -136,13 +136,15 @@ const actions = {
},
// user logout
- logout({ commit, state }) {
+ logout({ commit, state }, param) {
+ const method = param && param.casEnable ? deLogout : logout
return new Promise((resolve, reject) => {
- logout(state.token).then(() => {
+ method(state.token).then(res => {
+ debugger
removeToken() // must remove token first
resetRouter()
commit('RESET_STATE')
- resolve()
+ resolve(res.data)
}).catch(error => {
reject(error)
})
diff --git a/frontend/src/utils/auth.js b/frontend/src/utils/auth.js
index e8093dcd03..b5d3ed9f7f 100644
--- a/frontend/src/utils/auth.js
+++ b/frontend/src/utils/auth.js
@@ -7,6 +7,8 @@ const IdTokenKey = Config.IdTokenKey
const AccessTokenKey = Config.AccessTokenKey
+const casSessionKey = Config.CASSESSION
+
const linkTokenKey = Config.LinkTokenKey
export function getIdToken() {
@@ -22,6 +24,7 @@ export function setToken(token) {
}
export function removeToken() {
+ Cookies.remove(casSessionKey)
Cookies.remove(IdTokenKey)
Cookies.remove(AccessTokenKey)
return Cookies.remove(TokenKey)
diff --git a/frontend/src/views/system/SysParam/BasicSetting.vue b/frontend/src/views/system/SysParam/BasicSetting.vue
index 6e3657abe1..f242ebff5b 100644
--- a/frontend/src/views/system/SysParam/BasicSetting.vue
+++ b/frontend/src/views/system/SysParam/BasicSetting.vue
@@ -38,6 +38,7 @@
{{ $t('login.default_login') }}
LDAP
OIDC
+ CAS
@@ -67,8 +68,8 @@