parent
8bf4ce16a6
commit
7e6a08bef2
|
@ -1,18 +1,35 @@
|
||||||
package io.metersphere.commons.user;
|
package io.metersphere.commons.user;
|
||||||
|
|
||||||
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
import io.metersphere.dto.UserDTO;
|
import io.metersphere.dto.UserDTO;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
public class SessionUser extends UserDTO implements Serializable {
|
public class SessionUser extends UserDTO implements Serializable {
|
||||||
|
public static final String secret = "9a9rdqPlTqhpZzkq";
|
||||||
|
public static final String iv = "1Av7hf9PgHusUHRm";
|
||||||
|
|
||||||
private static final long serialVersionUID = -7149638440406959033L;
|
private static final long serialVersionUID = -7149638440406959033L;
|
||||||
|
private String csrfToken;
|
||||||
|
|
||||||
|
private SessionUser() {
|
||||||
|
}
|
||||||
|
|
||||||
public static SessionUser fromUser(UserDTO user) {
|
public static SessionUser fromUser(UserDTO user) {
|
||||||
SessionUser sessionUser = new SessionUser();
|
SessionUser sessionUser = new SessionUser();
|
||||||
BeanUtils.copyProperties(user, sessionUser);
|
BeanUtils.copyProperties(user, sessionUser);
|
||||||
|
|
||||||
|
List<String> infos = Arrays.asList(user.getId(), RandomStringUtils.random(6), "" + System.currentTimeMillis());
|
||||||
|
sessionUser.csrfToken = CodingUtil.aesEncrypt(StringUtils.join(infos, "|"), secret, iv);
|
||||||
return sessionUser;
|
return sessionUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,14 +62,14 @@ public class SessionUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCurrentWorkspaceId() {
|
public static String getCurrentWorkspaceId() {
|
||||||
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastWorkspaceId();
|
return getUser().getLastWorkspaceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCurrentOrganizationId() {
|
public static String getCurrentOrganizationId() {
|
||||||
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastOrganizationId();
|
return getUser().getLastOrganizationId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCurrentProjectId() {
|
public static String getCurrentProjectId() {
|
||||||
return Optional.ofNullable(getUser()).orElse(new SessionUser()).getLastProjectId();
|
return getUser().getLastProjectId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.config;
|
||||||
|
|
||||||
import io.metersphere.commons.utils.ShiroUtils;
|
import io.metersphere.commons.utils.ShiroUtils;
|
||||||
import io.metersphere.security.ApiKeyFilter;
|
import io.metersphere.security.ApiKeyFilter;
|
||||||
|
import io.metersphere.security.CsrfFilter;
|
||||||
import io.metersphere.security.UserModularRealmAuthenticator;
|
import io.metersphere.security.UserModularRealmAuthenticator;
|
||||||
import io.metersphere.security.realm.LdapRealm;
|
import io.metersphere.security.realm.LdapRealm;
|
||||||
import io.metersphere.security.realm.ShiroDBRealm;
|
import io.metersphere.security.realm.ShiroDBRealm;
|
||||||
|
@ -44,10 +45,11 @@ public class ShiroConfig implements EnvironmentAware {
|
||||||
shiroFilterFactoryBean.setSuccessUrl("/");
|
shiroFilterFactoryBean.setSuccessUrl("/");
|
||||||
|
|
||||||
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
|
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
|
||||||
|
shiroFilterFactoryBean.getFilters().put("csrf", new CsrfFilter());
|
||||||
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
|
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
|
||||||
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
|
ShiroUtils.loadBaseFilterChain(filterChainDefinitionMap);
|
||||||
|
|
||||||
filterChainDefinitionMap.put("/**", "apikey, authc");
|
filterChainDefinitionMap.put("/**", "apikey, csrf, authc");
|
||||||
return shiroFilterFactoryBean;
|
return shiroFilterFactoryBean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package io.metersphere.controller;
|
package io.metersphere.controller;
|
||||||
|
|
||||||
import io.metersphere.commons.constants.SsoMode;
|
|
||||||
import io.metersphere.commons.constants.UserSource;
|
import io.metersphere.commons.constants.UserSource;
|
||||||
import io.metersphere.commons.user.SessionUser;
|
import io.metersphere.commons.user.SessionUser;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
|
@ -10,7 +9,6 @@ import io.metersphere.service.UserService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@ -24,8 +22,6 @@ public class LoginController {
|
||||||
@Resource
|
@Resource
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
@Resource
|
@Resource
|
||||||
private Environment env;
|
|
||||||
@Resource
|
|
||||||
private BaseDisplayService baseDisplayService;
|
private BaseDisplayService baseDisplayService;
|
||||||
|
|
||||||
@GetMapping(value = "/isLogin")
|
@GetMapping(value = "/isLogin")
|
||||||
|
@ -37,10 +33,6 @@ public class LoginController {
|
||||||
}
|
}
|
||||||
return ResultHolder.success(user);
|
return ResultHolder.success(user);
|
||||||
}
|
}
|
||||||
String ssoMode = env.getProperty("sso.mode");
|
|
||||||
if (ssoMode != null && StringUtils.equalsIgnoreCase(SsoMode.CAS.name(), ssoMode)) {
|
|
||||||
return ResultHolder.error("sso");
|
|
||||||
}
|
|
||||||
return ResultHolder.error("");
|
return ResultHolder.error("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package io.metersphere.controller;
|
package io.metersphere.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.base.domain.Organization;
|
|
||||||
import io.metersphere.base.domain.User;
|
import io.metersphere.base.domain.User;
|
||||||
import io.metersphere.base.domain.Workspace;
|
|
||||||
import io.metersphere.commons.constants.RoleConstants;
|
import io.metersphere.commons.constants.RoleConstants;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.user.SessionUser;
|
import io.metersphere.commons.user.SessionUser;
|
||||||
|
@ -29,7 +26,6 @@ import io.metersphere.service.WorkspaceService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.Logical;
|
||||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||||
import org.checkerframework.checker.units.qual.C;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package io.metersphere.security;
|
||||||
|
|
||||||
|
import io.metersphere.commons.user.SessionUser;
|
||||||
|
import io.metersphere.commons.utils.CodingUtil;
|
||||||
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.web.filter.authc.AnonymousFilter;
|
||||||
|
import org.apache.shiro.web.util.WebUtils;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
public class CsrfFilter extends AnonymousFilter {
|
||||||
|
private static final String TOKEN_NAME = "CSRF-TOKEN";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||||
|
HttpServletRequest httpServletRequest = WebUtils.toHttp(request);
|
||||||
|
|
||||||
|
if (!SecurityUtils.getSubject().isAuthenticated()) {
|
||||||
|
((HttpServletResponse) response).setHeader("Authentication-Status", "invalid");
|
||||||
|
}
|
||||||
|
// api 过来的请求
|
||||||
|
if (ApiKeyHandler.isApiKeyCall(WebUtils.toHttp(request))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 请求头取出的token value
|
||||||
|
String csrfToken = httpServletRequest.getHeader(TOKEN_NAME);
|
||||||
|
// 校验
|
||||||
|
validate(csrfToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate(String csrfToken) {
|
||||||
|
csrfToken = CodingUtil.aesDecrypt(csrfToken, SessionUser.secret, SessionUser.iv);
|
||||||
|
|
||||||
|
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(csrfToken), "|");
|
||||||
|
if (signatureArray.length != 3) {
|
||||||
|
throw new RuntimeException("invalid token");
|
||||||
|
}
|
||||||
|
|
||||||
|
long signatureTime;
|
||||||
|
try {
|
||||||
|
signatureTime = Long.parseLong(signatureArray[2]);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
Environment env = CommonBeanFactory.getBean(Environment.class);
|
||||||
|
assert env != null;
|
||||||
|
long timeout = env.getProperty("session.timeout", Long.class, 43200L);
|
||||||
|
if (Math.abs(System.currentTimeMillis() - signatureTime) > timeout * 1000) {
|
||||||
|
throw new RuntimeException("expired token");
|
||||||
|
}
|
||||||
|
if (!StringUtils.equals(SessionUtils.getUserId(), signatureArray[0])) {
|
||||||
|
throw new RuntimeException("Please check csrf token.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import {Message, MessageBox} from 'element-ui';
|
import {Message, MessageBox} from 'element-ui';
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import i18n from '../../i18n/i18n'
|
import i18n from '../../i18n/i18n'
|
||||||
|
import {TokenKey} from "@/common/js/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
install(Vue) {
|
install(Vue) {
|
||||||
|
@ -40,6 +40,15 @@ export default {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
axios.interceptors.request.use(config => {
|
||||||
|
let user = JSON.parse(localStorage.getItem(TokenKey));
|
||||||
|
if (user && user.csrfToken) {
|
||||||
|
config.headers['CSRF-TOKEN'] = user.csrfToken;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function then(success, response, result) {
|
function then(success, response, result) {
|
||||||
if (!response.data) {
|
if (!response.data) {
|
||||||
success(response);
|
success(response);
|
||||||
|
|
Loading…
Reference in New Issue