diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java index bf798725bc..3518d93f63 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/config/ShiroConfig.java @@ -4,6 +4,7 @@ package io.metersphere.sdk.config; import io.metersphere.sdk.security.ApiKeyFilter; import io.metersphere.sdk.security.CsrfFilter; import io.metersphere.sdk.security.MsPermissionAnnotationMethodInterceptor; +import io.metersphere.sdk.security.TotpFilter; import io.metersphere.sdk.security.realm.LocalRealm; import io.metersphere.sdk.util.FilterChainUtils; import jakarta.servlet.DispatcherType; @@ -42,10 +43,13 @@ public class ShiroConfig { shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter()); shiroFilterFactoryBean.getFilters().put("csrf", new CsrfFilter()); + shiroFilterFactoryBean.getFilters().put("totp", new TotpFilter()); Map filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap(); filterChainDefinitionMap.putAll(FilterChainUtils.loadBaseFilterChain()); + filterChainDefinitionMap.putAll(FilterChainUtils.totpFilterChain()); + filterChainDefinitionMap.putAll(FilterChainUtils.ignoreCsrfFilter()); filterChainDefinitionMap.put("/**", "apikey, csrf, authc"); diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java new file mode 100644 index 0000000000..ee016f6937 --- /dev/null +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/security/TotpFilter.java @@ -0,0 +1,38 @@ +package io.metersphere.sdk.security; + + +import com.bastiaanjansen.otp.TOTPGenerator; +import io.metersphere.sdk.constants.MsHttpHeaders; +import io.metersphere.sdk.util.CommonBeanFactory; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import org.apache.commons.lang.StringUtils; +import org.apache.shiro.web.filter.authc.AnonymousFilter; +import org.apache.shiro.web.util.WebUtils; + +public class TotpFilter extends AnonymousFilter { + + @Override + protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) { + HttpServletRequest httpServletRequest = WebUtils.toHttp(request); + + // 请求头取出的token value + String token = httpServletRequest.getHeader(MsHttpHeaders.OTP_TOKEN); + // 校验 token + validateToken(token); + + return true; + } + + private void validateToken(String token) { + if (StringUtils.isBlank(token)) { + throw new RuntimeException("token is empty"); + } + + TOTPGenerator totpGenerator = CommonBeanFactory.getBean(TOTPGenerator.class); + if (!totpGenerator.verify(token)) { + throw new RuntimeException("token is not valid"); + } + } +} diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java index 0d5bd3dd2e..dda6d055e7 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/util/FilterChainUtils.java @@ -22,9 +22,8 @@ public class FilterChainUtils { filterChainDefinitionMap.put("/display/info", "anon"); filterChainDefinitionMap.put("/favicon.ico", "anon"); filterChainDefinitionMap.put("/base-display/**", "anon"); - filterChainDefinitionMap.put("/jmeter/download/**", "anon"); filterChainDefinitionMap.put("/jmeter/ping", "anon"); - filterChainDefinitionMap.put("/jmeter/ready/**", "anon"); + filterChainDefinitionMap.put("/jmeter/ready/**", "totp"); filterChainDefinitionMap.put("/authsource/list/allenable", "anon"); filterChainDefinitionMap.put("/sso/callback/**", "anon"); filterChainDefinitionMap.put("/license/validate", "anon"); @@ -72,4 +71,11 @@ public class FilterChainUtils { filterChainDefinitionMap.put("/mock", "apikey, authc"); // 跳转到 /mock接口 不用校验 csrf return filterChainDefinitionMap; } + + public static Map totpFilterChain() { + Map filterChainDefinitionMap = new HashMap<>(); + // 执行机下载执行资源需要验证totp + filterChainDefinitionMap.put("/jmeter/download/**", "totp"); + return filterChainDefinitionMap; + } }