diff --git a/backend/pom.xml b/backend/pom.xml
index bdd4e17897..3ce4f9ac77 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -272,6 +272,24 @@
runtime
+
+
+ org.pac4j
+ pac4j-cas
+ 3.0.2
+
+
+ io.buji
+ buji-pac4j
+ 4.0.0
+
+
+ shiro-web
+ org.apache.shiro
+
+
+
+
diff --git a/backend/src/main/java/io/metersphere/commons/constants/OssMode.java b/backend/src/main/java/io/metersphere/commons/constants/OssMode.java
new file mode 100644
index 0000000000..aeb142a55b
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/commons/constants/OssMode.java
@@ -0,0 +1,5 @@
+package io.metersphere.commons.constants;
+
+public enum OssMode {
+ CAS,LOCAL
+}
diff --git a/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java
new file mode 100644
index 0000000000..2cf98d199a
--- /dev/null
+++ b/backend/src/main/java/io/metersphere/commons/utils/ShiroUtils.java
@@ -0,0 +1,53 @@
+package io.metersphere.commons.utils;
+
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.web.servlet.Cookie;
+import org.apache.shiro.web.servlet.SimpleCookie;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+
+import java.util.Map;
+
+public class ShiroUtils {
+
+ public static void loadBaseFilterChain(Map filterChainDefinitionMap){
+
+ filterChainDefinitionMap.put("/resource/**", "anon");
+ filterChainDefinitionMap.put("/signin", "anon");
+ filterChainDefinitionMap.put("/ldap/signin", "anon");
+ filterChainDefinitionMap.put("/ldap/open", "anon");
+ filterChainDefinitionMap.put("/isLogin", "anon");
+ filterChainDefinitionMap.put("/css/**", "anon");
+ filterChainDefinitionMap.put("/js/**", "anon");
+ filterChainDefinitionMap.put("/img/**", "anon");
+ filterChainDefinitionMap.put("/fonts/**", "anon");
+
+ // for swagger
+ filterChainDefinitionMap.put("/swagger-ui.html", "anon");
+ filterChainDefinitionMap.put("/swagger-ui/**", "anon");
+ filterChainDefinitionMap.put("/v3/api-docs/**", "anon");
+
+ filterChainDefinitionMap.put("/403", "anon");
+ filterChainDefinitionMap.put("/anonymous/**", "anon");
+ }
+
+ public static Cookie getSessionIdCookie(){
+ SimpleCookie sessionIdCookie = new SimpleCookie();
+ sessionIdCookie.setPath("/");
+ sessionIdCookie.setName("MS_SESSION_ID");
+ return sessionIdCookie;
+ }
+
+ public static SessionManager getSessionManager(Long sessionTimeout, CacheManager cacheManager){
+ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+ sessionManager.setSessionIdUrlRewritingEnabled(false);
+ sessionManager.setDeleteInvalidSessions(true);
+ sessionManager.setSessionValidationSchedulerEnabled(true);
+ sessionManager.setSessionIdCookie(ShiroUtils.getSessionIdCookie());
+ sessionManager.setGlobalSessionTimeout(sessionTimeout * 1000);// 超时时间ms
+ sessionManager.setCacheManager(cacheManager);
+
+ //sessionManager.setSessionIdCookieEnabled(true);
+ return sessionManager;
+ }
+}
diff --git a/backend/src/main/java/io/metersphere/config/ShiroConfig.java b/backend/src/main/java/io/metersphere/config/ShiroConfig.java
index a5b65170cf..a6dc567cef 100644
--- a/backend/src/main/java/io/metersphere/config/ShiroConfig.java
+++ b/backend/src/main/java/io/metersphere/config/ShiroConfig.java
@@ -1,5 +1,6 @@
package io.metersphere.config;
+import io.metersphere.commons.utils.ShiroUtils;
import io.metersphere.security.ApiKeyFilter;
import io.metersphere.security.LoginFilter;
import io.metersphere.security.ShiroDBRealm;
@@ -9,9 +10,8 @@ import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
-import org.apache.shiro.web.servlet.SimpleCookie;
-import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.EnvironmentAware;
@@ -29,6 +29,7 @@ import java.util.Map;
import java.util.Objects;
@Configuration
+@ConditionalOnProperty(prefix="oss",name = "mode", havingValue = "local", matchIfMissing = true)
public class ShiroConfig implements EnvironmentAware {
private Environment env;
@@ -42,26 +43,8 @@ public class ShiroConfig implements EnvironmentAware {
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
-
Map filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
- filterChainDefinitionMap.put("/resource/**", "anon");
- filterChainDefinitionMap.put("/", "anon");
- filterChainDefinitionMap.put("/signin", "anon");
- filterChainDefinitionMap.put("/ldap/signin", "anon");
- filterChainDefinitionMap.put("/ldap/open", "anon");
- filterChainDefinitionMap.put("/isLogin", "anon");
- filterChainDefinitionMap.put("/css/**", "anon");
- filterChainDefinitionMap.put("/js/**", "anon");
- filterChainDefinitionMap.put("/img/**", "anon");
- filterChainDefinitionMap.put("/fonts/**", "anon");
-
- // for swagger
- filterChainDefinitionMap.put("/swagger-ui.html", "anon");
- filterChainDefinitionMap.put("/swagger-ui/**", "anon");
- filterChainDefinitionMap.put("/v3/api-docs/**", "anon");
-
- filterChainDefinitionMap.put("/403", "anon");
- filterChainDefinitionMap.put("/anonymous/**", "anon");
+ ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
filterChainDefinitionMap.put("/**", "apikey, authc");
return shiroFilterFactoryBean;
}
@@ -120,18 +103,7 @@ public class ShiroConfig implements EnvironmentAware {
@Bean
public SessionManager sessionManager(MemoryConstrainedCacheManager memoryConstrainedCacheManager) {
Long sessionTimeout = env.getProperty("session.timeout", Long.class, 1800L); // 默认1800s, 半个小时
-
- DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
- sessionManager.setSessionIdUrlRewritingEnabled(false);
- sessionManager.setGlobalSessionTimeout(sessionTimeout * 1000);// 超时时间ms
- sessionManager.setDeleteInvalidSessions(true);
- sessionManager.setSessionValidationSchedulerEnabled(true);
- SimpleCookie sessionIdCookie = new SimpleCookie();
- sessionManager.setSessionIdCookie(sessionIdCookie);
- sessionIdCookie.setPath("/");
- sessionIdCookie.setName("MS_SESSION_ID");
- sessionManager.setCacheManager(memoryConstrainedCacheManager);
- return sessionManager;
+ return ShiroUtils.getSessionManager(sessionTimeout, memoryConstrainedCacheManager);
}
/**
diff --git a/backend/src/main/java/io/metersphere/controller/IndexController.java b/backend/src/main/java/io/metersphere/controller/IndexController.java
index 868b253dd3..8bbd67e76d 100644
--- a/backend/src/main/java/io/metersphere/controller/IndexController.java
+++ b/backend/src/main/java/io/metersphere/controller/IndexController.java
@@ -1,6 +1,7 @@
package io.metersphere.controller;
import io.metersphere.commons.utils.SessionUtils;
+import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -22,4 +23,15 @@ public class IndexController {
return "redirect:/";
}
}
+
+ @GetMapping(value = "/oss/login")
+ public String ossLogin() {
+ return "redirect:/";
+ }
+
+ @GetMapping(value = "/oss/logout")
+ public void ossLogout() {
+ SecurityUtils.getSubject().logout();
+ }
+
}
diff --git a/backend/src/main/java/io/metersphere/controller/LoginController.java b/backend/src/main/java/io/metersphere/controller/LoginController.java
index 997df80108..9b2b8987d9 100644
--- a/backend/src/main/java/io/metersphere/controller/LoginController.java
+++ b/backend/src/main/java/io/metersphere/controller/LoginController.java
@@ -1,10 +1,15 @@
package io.metersphere.controller;
+import io.metersphere.commons.constants.OssMode;
import io.metersphere.commons.constants.UserSource;
+import io.metersphere.commons.user.SessionUser;
+import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.controller.request.LoginRequest;
import io.metersphere.service.UserService;
+import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@@ -15,11 +20,21 @@ public class LoginController {
@Resource
private UserService userService;
+ @Resource
+ private Environment env;
@GetMapping(value = "/isLogin")
public ResultHolder isLogin() {
if (SecurityUtils.getSubject().isAuthenticated()) {
- return ResultHolder.success(LocaleContextHolder.getLocale());
+ SessionUser user = SessionUtils.getUser();
+ if (StringUtils.isBlank(user.getLanguage())) {
+ user.setLanguage(LocaleContextHolder.getLocale().toString());
+ }
+ return ResultHolder.success(user);
+ }
+ String ossMode = env.getProperty("oss.mode");
+ if (ossMode != null && StringUtils.equalsIgnoreCase(OssMode.CAS.name(), ossMode)) {
+ return ResultHolder.error("oss");
}
return ResultHolder.error("");
}
@@ -30,9 +45,19 @@ public class LoginController {
return userService.login(request);
}
+ @GetMapping(value = "/currentUser")
+ public ResultHolder currentUser() {
+ return ResultHolder.success(SecurityUtils.getSubject().getSession().getAttribute("user"));
+ }
+
@GetMapping(value = "/signout")
public ResultHolder logout() {
- SecurityUtils.getSubject().logout();
+ String ossMode = env.getProperty("oss.mode");
+ if (ossMode != null && StringUtils.equalsIgnoreCase(OssMode.CAS.name(), ossMode)) {
+ return ResultHolder.error("oss");
+ } else {
+ SecurityUtils.getSubject().logout();
+ }
return ResultHolder.success("");
}
@@ -42,5 +67,4 @@ public class LoginController {
return userService.getDefaultLanguage();
}
-
}
diff --git a/backend/src/main/java/io/metersphere/dto/UserDTO.java b/backend/src/main/java/io/metersphere/dto/UserDTO.java
index 944c2a62a3..ca7753babc 100644
--- a/backend/src/main/java/io/metersphere/dto/UserDTO.java
+++ b/backend/src/main/java/io/metersphere/dto/UserDTO.java
@@ -1,6 +1,7 @@
package io.metersphere.dto;
import io.metersphere.base.domain.Role;
+import io.metersphere.base.domain.User;
import io.metersphere.base.domain.UserRole;
import lombok.Getter;
import lombok.Setter;
@@ -10,28 +11,7 @@ import java.util.List;
@Getter
@Setter
-public class UserDTO {
- private String id;
-
- private String name;
-
- private String email;
-
- private String phone;
-
- private String status;
-
- private String source;
-
- private Long createTime;
-
- private Long updateTime;
-
- private String language;
-
- private String lastWorkspaceId;
-
- private String lastOrganizationId;
+public class UserDTO extends User {
private List roles = new ArrayList<>();
diff --git a/backend/src/main/java/io/metersphere/security/ShiroDBRealm.java b/backend/src/main/java/io/metersphere/security/ShiroDBRealm.java
index 30927a2ef2..71a2bef3b8 100644
--- a/backend/src/main/java/io/metersphere/security/ShiroDBRealm.java
+++ b/backend/src/main/java/io/metersphere/security/ShiroDBRealm.java
@@ -49,15 +49,16 @@ public class ShiroDBRealm extends AuthorizingRealm {
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+ String userId = (String) principals.getPrimaryPrincipal();
+ return getAuthorizationInfo(userId, userService);
+ }
- String userName = (String) principals.getPrimaryPrincipal();
+ public static AuthorizationInfo getAuthorizationInfo(String userId, UserService userService) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
-
// roles 内容填充
- UserDTO userDTO = userService.getUserDTO(userName);
+ UserDTO userDTO = userService.getUserDTO(userId);
Set roles = userDTO.getRoles().stream().map(Role::getId).collect(Collectors.toSet());
authorizationInfo.setRoles(roles);
-
return authorizationInfo;
}
@@ -148,7 +149,6 @@ public class ShiroDBRealm extends AuthorizingRealm {
if (!userService.checkUserPassword(userId, password)) {
throw new IncorrectCredentialsException(Translator.get("password_is_incorrect"));
}
- //
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
diff --git a/backend/src/main/java/io/metersphere/service/UserService.java b/backend/src/main/java/io/metersphere/service/UserService.java
index 6895df41b1..ebeb4155b9 100644
--- a/backend/src/main/java/io/metersphere/service/UserService.java
+++ b/backend/src/main/java/io/metersphere/service/UserService.java
@@ -163,6 +163,17 @@ public class UserService {
userMapper.insertSelective(user);
}
+ public void createOssUser(User user) {
+ user.setCreateTime(System.currentTimeMillis());
+ user.setUpdateTime(System.currentTimeMillis());
+ user.setStatus(UserStatus.NORMAL);
+ if (StringUtils.isBlank(user.getEmail())) {
+ user.setEmail(user.getId() + "@metershpere.io");
+ }
+ userMapper.insertSelective(user);
+ }
+
+
private void checkEmailIsExist(String email) {
UserExample userExample = new UserExample();
UserExample.Criteria criteria = userExample.createCriteria();
diff --git a/frontend/src/business/App.vue b/frontend/src/business/App.vue
index ccd7c71aba..6f75a42fa0 100644
--- a/frontend/src/business/App.vue
+++ b/frontend/src/business/App.vue
@@ -25,6 +25,7 @@
import MsUser from "./components/common/head/HeaderUser";
import MsHeaderOrgWs from "./components/common/head/HeaderOrgWs";
import MsLanguageSwitch from "./components/common/head/LanguageSwitch";
+ import {saveLocalStorage} from "../common/js/utils";
export default {
name: 'app',
@@ -36,7 +37,8 @@
beforeCreate() {
this.$get("/isLogin").then(response => {
if (response.data.success) {
- this.$setLang(response.data.data);
+ this.$setLang(response.data.data.language);
+ saveLocalStorage(response.data);
this.auth = true;
} else {
window.location.href = "/login"
diff --git a/frontend/src/business/components/common/head/HeaderUser.vue b/frontend/src/business/components/common/head/HeaderUser.vue
index 6c07ed5557..02a8cd6a65 100644
--- a/frontend/src/business/components/common/head/HeaderUser.vue
+++ b/frontend/src/business/components/common/head/HeaderUser.vue
@@ -18,6 +18,7 @@