refactor: 适配cas

This commit is contained in:
chenjianxing 2020-08-17 10:09:19 +08:00
parent 6e7fe725a1
commit 064304ba28
12 changed files with 161 additions and 66 deletions

View File

@ -272,6 +272,24 @@
<scope>runtime</scope>
</dependency>
<!-- buji-pac4j -->
<dependency>
<groupId>org.pac4j</groupId>
<artifactId>pac4j-cas</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>io.buji</groupId>
<artifactId>buji-pac4j</artifactId>
<version>4.0.0</version>
<exclusions>
<exclusion>
<artifactId>shiro-web</artifactId>
<groupId>org.apache.shiro</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum OssMode {
CAS,LOCAL
}

View File

@ -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<String, String> 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;
}
}

View File

@ -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<String, String> 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);
}
/**

View File

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

View File

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

View File

@ -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<Role> roles = new ArrayList<>();

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@
<script>
import {getCurrentUser} from "../../../../common/js/utils";
import AboutUs from "./AboutUs";
import axios from "axios";
export default {
name: "MsUser",
@ -35,7 +36,17 @@
this.$router.push('/setting/personsetting').catch(error => error);
break;
case "logout":
this.$get("/signout", function () {
axios.get("/signout").then(response => {
if (response.data.success) {
localStorage.clear();
window.location.href = "/login";
} else {
if (response.data.message === 'oss') {
localStorage.clear();
window.location.href = "/oss/logout"
}
}
}).catch(error => {
localStorage.clear();
window.location.href = "/login";
});

View File

@ -88,8 +88,15 @@
beforeCreate() {
this.$get("/isLogin").then(response => {
if (!response.data.success) {
this.ready = true;
if (response.data.message === 'oss') {
window.location.href = "/oss/login"
} else {
this.ready = true;
}
} else {
let user = response.data.data;
saveLocalStorage(user);
this.getLanguage(user.language);
window.location.href = "/"
}
});