diff --git a/README.md b/README.md index 61266e26..911864ef 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ 2. 修改zyplayer-doc-manage项目的application.yml配置文件里面的数据库账号密码 3. 启动zyplayer-doc-manage项目,访问地址: -http://127.0.0.1:8082/zyplayer-doc-manage/statics/manage/home.html +http://127.0.0.1:8082/zyplayer-doc-manage/static/manage/home.html 未登录会进入登录页面,登陆后自动跳回,默认账号:zyplayer 密码:123456 > 项目页面全是静态的html,如果使用idea启动,有可能访问不了静态页面,需要在这里配置下工作目录,然后重新启动即可 ![](https://images.gitee.com/uploads/images/2019/0127/222951_4ce343fe_596905.png "配置工作目录") diff --git a/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/MgStorageServiceImpl.java b/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/MgStorageServiceImpl.java index f5d3690c..01ca808c 100644 --- a/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/MgStorageServiceImpl.java +++ b/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/MgStorageServiceImpl.java @@ -1,19 +1,20 @@ package com.zyplayer.doc.manage.framework.config; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.commons.lang.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.zyplayer.doc.manage.repository.manage.entity.ZyplayerStorage; import com.zyplayer.doc.manage.service.manage.ZyplayerStorageService; import com.zyplayer.doc.swagger.framework.service.MgStorage; import com.zyplayer.doc.swagger.framework.service.MgStorageService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; /** * 申明为@Service之后网页上才能使用存储能力,同时需要在@EnableSwagger2的地方添加@EnableSwaggerMgUi注解, @@ -21,14 +22,16 @@ import com.zyplayer.doc.swagger.framework.service.MgStorageService; * 开放存储能力的好处:
* 所有网页的配置、调试值都可以存储到服务器的数据库中,便于团队所有人的调试,一人配置,所有人受益
* 如果不开启的话,数据是存放在浏览器的localStorage中,每个人、每个浏览器都得配置一次才能使用
- * + * * @author 暮光:城中城 * @since 2018年8月19日 */ @Service public class MgStorageServiceImpl implements MgStorageService { - - @Autowired + + @Value("${zyplayer.doc.swagger.proxy-request.white-domain}") + private String proxyRequestWhiteDomain; + @Resource ZyplayerStorageService zyplayerStorageService; /** @@ -54,10 +57,7 @@ public class MgStorageServiceImpl implements MgStorageService { if (storageList == null || storageList.isEmpty()) { return Collections.emptyList(); } - List resultList = storageList.stream().map(val -> { - return new MgStorage(val.getDocKey(), val.getDocValue()); - }).collect(Collectors.toList()); - return resultList; + return storageList.stream().map(val -> new MgStorage(val.getDocKey(), val.getDocValue())).collect(Collectors.toList()); } /** @@ -87,5 +87,13 @@ public class MgStorageServiceImpl implements MgStorageService { queryWrapper.eq("doc_key", key); zyplayerStorageService.remove(queryWrapper); } - + + @Override + public List getProxyRequestWhiteDomain() { + if (StringUtils.isBlank(proxyRequestWhiteDomain)) { + return Collections.emptyList(); + } + return Arrays.asList(proxyRequestWhiteDomain.split(";")); + } + } diff --git a/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/security/WebSecurityConfig.java b/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/security/WebSecurityConfig.java index c95aec1a..9f43a8ba 100644 --- a/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/security/WebSecurityConfig.java +++ b/zyplayer-doc-manage/src/main/java/com/zyplayer/doc/manage/framework/config/security/WebSecurityConfig.java @@ -39,41 +39,52 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { */ @Override public void configure(WebSecurity web) throws Exception { - web.ignoring().antMatchers("/static/lib/**", "/css/**", "/js/**", "/img/**"); + web.ignoring().antMatchers(); } @Override protected void configure(HttpSecurity http) throws Exception { String loginPage = "/static/manage/login.html"; - + // 无需登录即可访问的接口 + String[] permitAllAntPatterns = { + // 登录接口 + "/login/**", + // 开放接口的静态文件和接口 + "/open-doc.html", "/webjars/open-doc/**", "/swagger-mg-ui/open-doc/**", + // http代理请求接口,有白名单限制,也不怕随便请求到内网资源了 + "/swagger-mg-ui/http/**", + // 静态资源 + "/webjars/zui/**", "/webjars/vue/**", "/static/lib/**" + }; + // 文档页面需要具有文档权限 + String[] docAntPatterns = { + "/document.html", "/doc-db.html", "/doc.html", "/swagger-ui.html", + "/swagger-mg-ui/document/**", "/swagger-mg-ui/storage/**", "/swagger-resources/**" + }; http.authorizeRequests() - .antMatchers( - "/login/**", "/open-doc.html", - "/webjars/open-doc/**", "/swagger-mg-ui/open-doc/**", - "/webjars/zui/**", "/webjars/vue/**" - ).permitAll()//为了测试其他功能,设置“ /** ”允许所有请求 - .antMatchers("/document.html", "/doc.html").hasAuthority("DOC_ALL") - // 其他地址的访问均需登录 - .anyRequest().authenticated().and() - // 添加验证码验证 - .addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) - .exceptionHandling() - .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(loginPage)) - .and().addFilterAt(rememberMeAuthenticationFilter(), RememberMeAuthenticationFilter.class) - // 指定登录页面的请求路径 - .formLogin().loginPage(loginPage) - // 登陆处理路径 - .loginProcessingUrl("/login").permitAll() - // 退出请求的默认路径为logout - .and().logout().deleteCookies("remember-me") - .logoutUrl("/logout").logoutSuccessUrl(loginPage) - .permitAll() - // 开启rememberMe,设置一个私钥专供testall项目使用,注意与下面TokenBasedRememberMeServices的key保持一致 - // .rememberMe().key("testallKey").and() - // 关闭csrf - .and().csrf().disable() - // X-Frame-Options: SAMEORIGIN 表示该页面可以在相同域名页面的 frame 中展示 - .headers().frameOptions().sameOrigin(); + .antMatchers(permitAllAntPatterns).permitAll() + .antMatchers(docAntPatterns).hasAuthority("DOC_ALL") + // 其他地址的访问均需登录 + .anyRequest().authenticated().and() + // 添加验证码验证 + .addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) + .exceptionHandling() + .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(loginPage)) + .and().addFilterAt(rememberMeAuthenticationFilter(), RememberMeAuthenticationFilter.class) + // 指定登录页面的请求路径 + .formLogin().loginPage(loginPage) + // 登陆处理路径 + .loginProcessingUrl("/login").permitAll() + // 退出请求的默认路径为logout + .and().logout().deleteCookies("remember-me") + .logoutUrl("/logout").logoutSuccessUrl(loginPage) + .permitAll() + // 开启rememberMe,设置一个私钥专供testall项目使用,注意与下面TokenBasedRememberMeServices的key保持一致 + // .rememberMe().key("testallKey").and() + // 关闭csrf + .and().csrf().disable() + // X-Frame-Options: SAMEORIGIN 表示该页面可以在相同域名页面的 frame 中展示 + .headers().frameOptions().sameOrigin(); } @Override diff --git a/zyplayer-doc-manage/src/main/resources/application.yml b/zyplayer-doc-manage/src/main/resources/application.yml index bdf34dd2..39e62337 100644 --- a/zyplayer-doc-manage/src/main/resources/application.yml +++ b/zyplayer-doc-manage/src/main/resources/application.yml @@ -11,6 +11,10 @@ server: zyplayer: doc: + swagger: + proxy-request: + # 内部访问时可以代理请求的域名,使用 ; 分割,必须设置,防止访问到内部地址资源 + white-domain: http://127.0.0.1/;http://www.baidu.com/;http://swagger-bootstrap-ui.xiaominfo.com/ # zyplayer_doc_manage管理端的数据库配置 manage: datasource: diff --git a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgDocumentController.java b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgDocumentController.java index 1c0912b7..254568cd 100644 --- a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgDocumentController.java +++ b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgDocumentController.java @@ -15,7 +15,6 @@ import com.zyplayer.doc.swagger.framework.service.MgStorageService; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.aop.support.AopUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @@ -86,38 +85,21 @@ public class MgDocumentController { + ":" + request.getServerPort() // 端口号 + request.getContextPath(); // 是否加入自身的文档 - Object enableSwaggerMgUi = SpringContextUtil.getBeanWithAnnotation(EnableSwaggerMgUi.class); - if (enableSwaggerMgUi != null) { - EnableSwaggerMgUi swaggerMgUi = enableSwaggerMgUi.getClass().getAnnotation(EnableSwaggerMgUi.class); - if (swaggerMgUi == null) { - // 直接通过superclass去找 - Class superclass = enableSwaggerMgUi.getClass().getSuperclass(); - if (superclass != null) { - swaggerMgUi = superclass.getAnnotation(EnableSwaggerMgUi.class); - } - } - if (swaggerMgUi == null) { - // 再通过AopUtils去找 - Class targetClass = AopUtils.getTargetClass(enableSwaggerMgUi); - if (targetClass != null) { - swaggerMgUi = targetClass.getAnnotation(EnableSwaggerMgUi.class); - } - } - if (swaggerMgUi == null) { + EnableSwaggerMgUi swaggerMgUi = SpringContextUtil.getEnableSwaggerMgUi(); + if (swaggerMgUi == null) { + resourcesSet.add(new SwaggerResourcesInfoVo(serverPath + "/swagger-resources")); + } else { + if (swaggerMgUi.selfDoc()) { resourcesSet.add(new SwaggerResourcesInfoVo(serverPath + "/swagger-resources")); - } else { - if (swaggerMgUi.selfDoc()) { - resourcesSet.add(new SwaggerResourcesInfoVo(serverPath + "/swagger-resources")); - } - // 启动后第一次访问没有数据情况下需要加载进来的swagger-resources地址 - String[] defaultResources = swaggerMgUi.defaultResources(); - for (String url : defaultResources) { - resourcesSet.add(new SwaggerResourcesInfoVo(url)); - } - String[] defaultLocation = swaggerMgUi.defaultLocation(); - for (String url : defaultLocation) { - locationList.add(new LocationListVo(url, "")); - } + } + // 启动后第一次访问没有数据情况下需要加载进来的swagger-resources地址 + String[] defaultResources = swaggerMgUi.defaultResources(); + for (String url : defaultResources) { + resourcesSet.add(new SwaggerResourcesInfoVo(url)); + } + String[] defaultLocation = swaggerMgUi.defaultLocation(); + for (String url : defaultLocation) { + locationList.add(new LocationListVo(url, "")); } } } diff --git a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgHttpRequestController.java b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgHttpRequestController.java index 061300e2..72f77b4a 100644 --- a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgHttpRequestController.java +++ b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/controller/MgHttpRequestController.java @@ -7,10 +7,12 @@ import com.zyplayer.doc.swagger.controller.param.HttpRequestParam; import com.zyplayer.doc.swagger.controller.vo.HttpCookieVo; import com.zyplayer.doc.swagger.controller.vo.HttpHeaderVo; import com.zyplayer.doc.swagger.controller.vo.HttpRequestVo; +import com.zyplayer.doc.swagger.framework.service.MgStorageService; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import java.net.HttpCookie; import java.util.ArrayList; import java.util.List; @@ -20,7 +22,7 @@ import java.util.stream.Collectors; /** * 后台代理网络请求的控制器 - * + * * @author 暮光:城中城 * @since 2018年8月21日 */ @@ -28,8 +30,20 @@ import java.util.stream.Collectors; @RequestMapping("/swagger-mg-ui/http") public class MgHttpRequestController { + @Resource + MgStorageService mgStorageService; + @PostMapping(value = "/request") public DocResponseJson post(HttpRequestParam param) { + String paramUrl = param.getUrl(); + List whiteDomain = mgStorageService.getProxyRequestWhiteDomain(); + if (whiteDomain == null || whiteDomain.isEmpty()) { + return DocResponseJson.warn("未设置代理请求白名单,不能代理请求"); + } + long inWhiteList = whiteDomain.stream().filter(paramUrl::startsWith).count(); + if (inWhiteList <= 0) { + return DocResponseJson.warn("该域名不在白名单内,不能代理请求"); + } HttpRequest request = param.createRequest(); HttpResponse response = request.execute(); HttpRequestVo httpRequestVo = new HttpRequestVo(); diff --git a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/configuration/SpringContextUtil.java b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/configuration/SpringContextUtil.java index 00405eae..d7054a4d 100644 --- a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/configuration/SpringContextUtil.java +++ b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/configuration/SpringContextUtil.java @@ -1,13 +1,14 @@ package com.zyplayer.doc.swagger.framework.configuration; -import java.lang.annotation.Annotation; -import java.util.Map; - +import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; +import java.lang.annotation.Annotation; +import java.util.Map; + /** * context工具类 */ @@ -15,6 +16,7 @@ import org.springframework.stereotype.Component; public class SpringContextUtil implements ApplicationContextAware { public static ApplicationContext context; + private static EnableSwaggerMgUi ENABLE_SWAGGER_MG_UI; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { @@ -50,5 +52,38 @@ public class SpringContextUtil implements ApplicationContextAware { } return null; } + + /** + * 获取EnableSwaggerMgUi + * @date 2019/1/29 12:58 + **/ + public static EnableSwaggerMgUi getEnableSwaggerMgUi() { + if (ENABLE_SWAGGER_MG_UI != null) { + return ENABLE_SWAGGER_MG_UI; + } + Object annotation = SpringContextUtil.getBeanWithAnnotation(EnableSwaggerMgUi.class); + if (annotation != null) { + EnableSwaggerMgUi swaggerMgUi = annotation.getClass().getAnnotation(EnableSwaggerMgUi.class); + if (swaggerMgUi == null) { + // 直接通过superclass去找 + Class superclass = annotation.getClass().getSuperclass(); + if (superclass != null) { + swaggerMgUi = superclass.getAnnotation(EnableSwaggerMgUi.class); + } + } + if (swaggerMgUi == null) { + // 再通过AopUtils去找 + Class targetClass = AopUtils.getTargetClass(annotation); + if (targetClass != null) { + swaggerMgUi = targetClass.getAnnotation(EnableSwaggerMgUi.class); + } + } + if (swaggerMgUi != null) { + ENABLE_SWAGGER_MG_UI = swaggerMgUi; + } + return swaggerMgUi; + } + return null; + } } diff --git a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/service/MgStorageService.java b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/service/MgStorageService.java index c389cb09..cabef295 100644 --- a/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/service/MgStorageService.java +++ b/zyplayer-doc-swagger/src/main/java/com/zyplayer/doc/swagger/framework/service/MgStorageService.java @@ -45,4 +45,11 @@ public interface MgStorageService { */ void remove(String key); -} \ No newline at end of file + /** + * 获取代理请求白名单 + * @author 暮光:城中城 + * @since 2018年8月19日 + */ + List getProxyRequestWhiteDomain(); + +} diff --git a/zyplayer-doc-swagger/src/main/resources/webjars/mg-ui/js/mg-ui-debug.js b/zyplayer-doc-swagger/src/main/resources/webjars/mg-ui/js/mg-ui-debug.js index 9a01ade8..47a5413d 100644 --- a/zyplayer-doc-swagger/src/main/resources/webjars/mg-ui/js/mg-ui-debug.js +++ b/zyplayer-doc-swagger/src/main/resources/webjars/mg-ui/js/mg-ui-debug.js @@ -113,6 +113,9 @@ $(document).ready(function(){ // debugger; // 模拟请求开始 postWithFile("swagger-mg-ui/http/request", formDataToServer, function(result){ + if (!validateResult(result)) { + return; + } var afterSendTime = new Date().getTime(); //console.log(result); var requestObj = result.data; diff --git a/zyplayer-doc-swagger/src/main/resources/webjars/open-doc/js/mg-ui-debug.js b/zyplayer-doc-swagger/src/main/resources/webjars/open-doc/js/mg-ui-debug.js index 418cac0b..4781aee7 100644 --- a/zyplayer-doc-swagger/src/main/resources/webjars/open-doc/js/mg-ui-debug.js +++ b/zyplayer-doc-swagger/src/main/resources/webjars/open-doc/js/mg-ui-debug.js @@ -113,6 +113,9 @@ $(document).ready(function(){ // debugger; // 模拟请求开始 postWithFile("swagger-mg-ui/http/request", formDataToServer, function(result){ + if (!validateResult(result)) { + return; + } var afterSendTime = new Date().getTime(); //console.log(result); var requestObj = result.data; diff --git a/zyplayer-doc-swagger/src/main/resources/webjars/zpages/debugDataConfig.html b/zyplayer-doc-swagger/src/main/resources/webjars/zpages/debugDataConfig.html index 745933bd..928f45dd 100644 --- a/zyplayer-doc-swagger/src/main/resources/webjars/zpages/debugDataConfig.html +++ b/zyplayer-doc-swagger/src/main/resources/webjars/zpages/debugDataConfig.html @@ -58,9 +58,6 @@ Toast.success("刷新成功!"); }, deleteDebugData: function(event){ - if(!confirm("确定要删除吗?")) { - return; - } var tr = $(event.currentTarget).parents("tr"); var index = tr.data("index"); var delKey = app.debugDataList[index].key; diff --git a/zyplayer-doc-swagger/src/main/resources/webjars/zpages/docUrlConfig.html b/zyplayer-doc-swagger/src/main/resources/webjars/zpages/docUrlConfig.html index 3a40fa44..0dd2fd0c 100644 --- a/zyplayer-doc-swagger/src/main/resources/webjars/zpages/docUrlConfig.html +++ b/zyplayer-doc-swagger/src/main/resources/webjars/zpages/docUrlConfig.html @@ -53,7 +53,7 @@