This is page 2 of 9. Use http://codebase.md/higress-group/himarket?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .cursor │ └── rules │ ├── api-style.mdc │ └── project-architecture.mdc ├── .gitignore ├── build.sh ├── deploy │ ├── docker │ │ ├── docker-compose.yml │ │ └── Docker部署说明.md │ └── helm │ ├── Chart.yaml │ ├── Helm部署说明.md │ ├── templates │ │ ├── _helpers.tpl │ │ ├── himarket-admin-cm.yaml │ │ ├── himarket-admin-deployment.yaml │ │ ├── himarket-admin-service.yaml │ │ ├── himarket-frontend-cm.yaml │ │ ├── himarket-frontend-deployment.yaml │ │ ├── himarket-frontend-service.yaml │ │ ├── himarket-server-cm.yaml │ │ ├── himarket-server-deployment.yaml │ │ ├── himarket-server-service.yaml │ │ ├── mysql.yaml │ │ └── serviceaccount.yaml │ └── values.yaml ├── LICENSE ├── NOTICE ├── pom.xml ├── portal-bootstrap │ ├── Dockerfile │ ├── pom.xml │ └── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── alibaba │ │ │ └── apiopenplatform │ │ │ ├── config │ │ │ │ ├── AsyncConfig.java │ │ │ │ ├── FilterConfig.java │ │ │ │ ├── PageConfig.java │ │ │ │ ├── RestTemplateConfig.java │ │ │ │ ├── SecurityConfig.java │ │ │ │ └── SwaggerConfig.java │ │ │ ├── filter │ │ │ │ └── PortalResolvingFilter.java │ │ │ └── PortalApplication.java │ │ └── resources │ │ └── application.yaml │ └── test │ └── java │ └── com │ └── alibaba │ └── apiopenplatform │ └── integration │ └── AdministratorAuthIntegrationTest.java ├── portal-dal │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── alibaba │ └── apiopenplatform │ ├── converter │ │ ├── AdpAIGatewayConfigConverter.java │ │ ├── APIGConfigConverter.java │ │ ├── APIGRefConfigConverter.java │ │ ├── ApiKeyConfigConverter.java │ │ ├── ConsumerAuthConfigConverter.java │ │ ├── GatewayConfigConverter.java │ │ ├── HigressConfigConverter.java │ │ ├── HigressRefConfigConverter.java │ │ ├── HmacConfigConverter.java │ │ ├── JsonConverter.java │ │ ├── JwtConfigConverter.java │ │ ├── NacosRefConfigConverter.java │ │ ├── PortalSettingConfigConverter.java │ │ ├── PortalUiConfigConverter.java │ │ └── ProductIconConverter.java │ ├── entity │ │ ├── Administrator.java │ │ ├── BaseEntity.java │ │ ├── Consumer.java │ │ ├── ConsumerCredential.java │ │ ├── ConsumerRef.java │ │ ├── Developer.java │ │ ├── DeveloperExternalIdentity.java │ │ ├── Gateway.java │ │ ├── NacosInstance.java │ │ ├── Portal.java │ │ ├── PortalDomain.java │ │ ├── Product.java │ │ ├── ProductPublication.java │ │ ├── ProductRef.java │ │ └── ProductSubscription.java │ ├── repository │ │ ├── AdministratorRepository.java │ │ ├── BaseRepository.java │ │ ├── ConsumerCredentialRepository.java │ │ ├── ConsumerRefRepository.java │ │ ├── ConsumerRepository.java │ │ ├── DeveloperExternalIdentityRepository.java │ │ ├── DeveloperRepository.java │ │ ├── GatewayRepository.java │ │ ├── NacosInstanceRepository.java │ │ ├── PortalDomainRepository.java │ │ ├── PortalRepository.java │ │ ├── ProductPublicationRepository.java │ │ ├── ProductRefRepository.java │ │ ├── ProductRepository.java │ │ └── SubscriptionRepository.java │ └── support │ ├── common │ │ ├── Encrypted.java │ │ ├── Encryptor.java │ │ └── User.java │ ├── consumer │ │ ├── AdpAIAuthConfig.java │ │ ├── APIGAuthConfig.java │ │ ├── ApiKeyConfig.java │ │ ├── ConsumerAuthConfig.java │ │ ├── HigressAuthConfig.java │ │ ├── HmacConfig.java │ │ └── JwtConfig.java │ ├── enums │ │ ├── APIGAPIType.java │ │ ├── ConsumerAuthType.java │ │ ├── ConsumerStatus.java │ │ ├── CredentialMode.java │ │ ├── DeveloperAuthType.java │ │ ├── DeveloperStatus.java │ │ ├── DomainType.java │ │ ├── GatewayType.java │ │ ├── GrantType.java │ │ ├── HigressAPIType.java │ │ ├── JwtAlgorithm.java │ │ ├── ProductIconType.java │ │ ├── ProductStatus.java │ │ ├── ProductType.java │ │ ├── ProtocolType.java │ │ ├── PublicKeyFormat.java │ │ ├── SourceType.java │ │ ├── SubscriptionStatus.java │ │ └── UserType.java │ ├── gateway │ │ ├── AdpAIGatewayConfig.java │ │ ├── APIGConfig.java │ │ ├── GatewayConfig.java │ │ └── HigressConfig.java │ ├── portal │ │ ├── AuthCodeConfig.java │ │ ├── IdentityMapping.java │ │ ├── JwtBearerConfig.java │ │ ├── OAuth2Config.java │ │ ├── OidcConfig.java │ │ ├── PortalSettingConfig.java │ │ ├── PortalUiConfig.java │ │ └── PublicKeyConfig.java │ └── product │ ├── APIGRefConfig.java │ ├── HigressRefConfig.java │ ├── NacosRefConfig.java │ └── ProductIcon.java ├── portal-server │ ├── pom.xml │ └── src │ └── main │ └── java │ └── com │ └── alibaba │ └── apiopenplatform │ ├── controller │ │ ├── AdministratorController.java │ │ ├── ConsumerController.java │ │ ├── DeveloperController.java │ │ ├── GatewayController.java │ │ ├── NacosController.java │ │ ├── OAuth2Controller.java │ │ ├── OidcController.java │ │ ├── PortalController.java │ │ └── ProductController.java │ ├── core │ │ ├── advice │ │ │ ├── ExceptionAdvice.java │ │ │ └── ResponseAdvice.java │ │ ├── annotation │ │ │ ├── AdminAuth.java │ │ │ ├── AdminOrDeveloperAuth.java │ │ │ └── DeveloperAuth.java │ │ ├── constant │ │ │ ├── CommonConstants.java │ │ │ ├── IdpConstants.java │ │ │ ├── JwtConstants.java │ │ │ └── Resources.java │ │ ├── event │ │ │ ├── DeveloperDeletingEvent.java │ │ │ ├── PortalDeletingEvent.java │ │ │ └── ProductDeletingEvent.java │ │ ├── exception │ │ │ ├── BusinessException.java │ │ │ └── ErrorCode.java │ │ ├── response │ │ │ └── Response.java │ │ ├── security │ │ │ ├── ContextHolder.java │ │ │ ├── DeveloperAuthenticationProvider.java │ │ │ └── JwtAuthenticationFilter.java │ │ └── utils │ │ ├── IdGenerator.java │ │ ├── PasswordHasher.java │ │ └── TokenUtil.java │ ├── dto │ │ ├── converter │ │ │ ├── InputConverter.java │ │ │ ├── NacosToGatewayToolsConverter.java │ │ │ └── OutputConverter.java │ │ ├── params │ │ │ ├── admin │ │ │ │ ├── AdminCreateParam.java │ │ │ │ ├── AdminLoginParam.java │ │ │ │ └── ResetPasswordParam.java │ │ │ ├── consumer │ │ │ │ ├── CreateConsumerParam.java │ │ │ │ ├── CreateCredentialParam.java │ │ │ │ ├── CreateSubscriptionParam.java │ │ │ │ ├── QueryConsumerParam.java │ │ │ │ ├── QuerySubscriptionParam.java │ │ │ │ └── UpdateCredentialParam.java │ │ │ ├── developer │ │ │ │ ├── CreateDeveloperParam.java │ │ │ │ ├── CreateExternalDeveloperParam.java │ │ │ │ ├── DeveloperLoginParam.java │ │ │ │ ├── QueryDeveloperParam.java │ │ │ │ ├── UnbindExternalIdentityParam.java │ │ │ │ ├── UpdateDeveloperParam.java │ │ │ │ └── UpdateDeveloperStatusParam.java │ │ │ ├── gateway │ │ │ │ ├── ImportGatewayParam.java │ │ │ │ ├── QueryAdpAIGatewayParam.java │ │ │ │ ├── QueryAPIGParam.java │ │ │ │ └── QueryGatewayParam.java │ │ │ ├── nacos │ │ │ │ ├── CreateNacosParam.java │ │ │ │ ├── QueryNacosNamespaceParam.java │ │ │ │ ├── QueryNacosParam.java │ │ │ │ └── UpdateNacosParam.java │ │ │ ├── portal │ │ │ │ ├── BindDomainParam.java │ │ │ │ ├── CreatePortalParam.java │ │ │ │ └── UpdatePortalParam.java │ │ │ └── product │ │ │ ├── CreateProductParam.java │ │ │ ├── CreateProductRefParam.java │ │ │ ├── PublishProductParam.java │ │ │ ├── QueryProductParam.java │ │ │ ├── QueryProductSubscriptionParam.java │ │ │ ├── UnPublishProductParam.java │ │ │ └── UpdateProductParam.java │ │ └── result │ │ ├── AdminResult.java │ │ ├── AdpGatewayInstanceResult.java │ │ ├── AdpMcpServerListResult.java │ │ ├── AdpMCPServerResult.java │ │ ├── APIConfigResult.java │ │ ├── APIGMCPServerResult.java │ │ ├── APIResult.java │ │ ├── AuthResult.java │ │ ├── ConsumerCredentialResult.java │ │ ├── ConsumerResult.java │ │ ├── DeveloperResult.java │ │ ├── GatewayMCPServerResult.java │ │ ├── GatewayResult.java │ │ ├── HigressMCPServerResult.java │ │ ├── IdpResult.java │ │ ├── IdpState.java │ │ ├── IdpTokenResult.java │ │ ├── MCPConfigResult.java │ │ ├── MCPServerResult.java │ │ ├── MseNacosResult.java │ │ ├── NacosMCPServerResult.java │ │ ├── NacosNamespaceResult.java │ │ ├── NacosResult.java │ │ ├── PageResult.java │ │ ├── PortalResult.java │ │ ├── ProductPublicationResult.java │ │ ├── ProductRefResult.java │ │ ├── ProductResult.java │ │ └── SubscriptionResult.java │ └── service │ ├── AdministratorService.java │ ├── AdpAIGatewayService.java │ ├── ConsumerService.java │ ├── DeveloperService.java │ ├── gateway │ │ ├── AdpAIGatewayOperator.java │ │ ├── AIGatewayOperator.java │ │ ├── APIGOperator.java │ │ ├── client │ │ │ ├── AdpAIGatewayClient.java │ │ │ ├── APIGClient.java │ │ │ ├── GatewayClient.java │ │ │ ├── HigressClient.java │ │ │ ├── PopGatewayClient.java │ │ │ └── SLSClient.java │ │ ├── factory │ │ │ └── HTTPClientFactory.java │ │ ├── GatewayOperator.java │ │ └── HigressOperator.java │ ├── GatewayService.java │ ├── IdpService.java │ ├── impl │ │ ├── AdministratorServiceImpl.java │ │ ├── ConsumerServiceImpl.java │ │ ├── DeveloperServiceImpl.java │ │ ├── GatewayServiceImpl.java │ │ ├── IdpServiceImpl.java │ │ ├── NacosServiceImpl.java │ │ ├── OAuth2ServiceImpl.java │ │ ├── OidcServiceImpl.java │ │ ├── PortalServiceImpl.java │ │ └── ProductServiceImpl.java │ ├── NacosService.java │ ├── OAuth2Service.java │ ├── OidcService.java │ ├── PortalService.java │ └── ProductService.java ├── portal-web │ ├── api-portal-admin │ │ ├── .env │ │ ├── .gitignore │ │ ├── bin │ │ │ ├── replace_var.py │ │ │ └── start.sh │ │ ├── Dockerfile │ │ ├── eslint.config.js │ │ ├── index.html │ │ ├── nginx.conf │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── proxy.conf │ │ ├── public │ │ │ ├── logo.png │ │ │ └── vite.svg │ │ ├── README.md │ │ ├── src │ │ │ ├── aliyunThemeToken.ts │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── assets │ │ │ │ └── react.svg │ │ │ ├── components │ │ │ │ ├── api-product │ │ │ │ │ ├── ApiProductApiDocs.tsx │ │ │ │ │ ├── ApiProductDashboard.tsx │ │ │ │ │ ├── ApiProductFormModal.tsx │ │ │ │ │ ├── ApiProductLinkApi.tsx │ │ │ │ │ ├── ApiProductOverview.tsx │ │ │ │ │ ├── ApiProductPolicy.tsx │ │ │ │ │ ├── ApiProductPortal.tsx │ │ │ │ │ ├── ApiProductUsageGuide.tsx │ │ │ │ │ ├── SwaggerUIWrapper.css │ │ │ │ │ └── SwaggerUIWrapper.tsx │ │ │ │ ├── common │ │ │ │ │ ├── AdvancedSearch.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── console │ │ │ │ │ ├── GatewayTypeSelector.tsx │ │ │ │ │ ├── ImportGatewayModal.tsx │ │ │ │ │ ├── ImportHigressModal.tsx │ │ │ │ │ ├── ImportMseNacosModal.tsx │ │ │ │ │ └── NacosTypeSelector.tsx │ │ │ │ ├── icons │ │ │ │ │ └── McpServerIcon.tsx │ │ │ │ ├── Layout.tsx │ │ │ │ ├── LayoutWrapper.tsx │ │ │ │ ├── portal │ │ │ │ │ ├── PortalConsumers.tsx │ │ │ │ │ ├── PortalDashboard.tsx │ │ │ │ │ ├── PortalDevelopers.tsx │ │ │ │ │ ├── PortalDomain.tsx │ │ │ │ │ ├── PortalFormModal.tsx │ │ │ │ │ ├── PortalOverview.tsx │ │ │ │ │ ├── PortalPublishedApis.tsx │ │ │ │ │ ├── PortalSecurity.tsx │ │ │ │ │ ├── PortalSettings.tsx │ │ │ │ │ ├── PublicKeyManager.tsx │ │ │ │ │ └── ThirdPartyAuthManager.tsx │ │ │ │ └── subscription │ │ │ │ └── SubscriptionListModal.tsx │ │ │ ├── contexts │ │ │ │ └── LoadingContext.tsx │ │ │ ├── index.css │ │ │ ├── lib │ │ │ │ ├── api.ts │ │ │ │ ├── constant.ts │ │ │ │ └── utils.ts │ │ │ ├── main.tsx │ │ │ ├── pages │ │ │ │ ├── ApiProductDetail.tsx │ │ │ │ ├── ApiProducts.tsx │ │ │ │ ├── Dashboard.tsx │ │ │ │ ├── GatewayConsoles.tsx │ │ │ │ ├── Login.tsx │ │ │ │ ├── NacosConsoles.tsx │ │ │ │ ├── PortalDetail.tsx │ │ │ │ ├── Portals.tsx │ │ │ │ └── Register.tsx │ │ │ ├── routes │ │ │ │ └── index.tsx │ │ │ ├── types │ │ │ │ ├── api-product.ts │ │ │ │ ├── consumer.ts │ │ │ │ ├── gateway.ts │ │ │ │ ├── index.ts │ │ │ │ ├── portal.ts │ │ │ │ ├── shims-js-yaml.d.ts │ │ │ │ └── subscription.ts │ │ │ └── vite-env.d.ts │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── tsconfig.node.json │ │ └── vite.config.ts │ └── api-portal-frontend │ ├── .env │ ├── .gitignore │ ├── .husky │ │ └── pre-commit │ ├── bin │ │ ├── replace_var.py │ │ └── start.sh │ ├── Dockerfile │ ├── eslint.config.js │ ├── index.html │ ├── nginx.conf │ ├── package.json │ ├── postcss.config.js │ ├── proxy.conf │ ├── public │ │ ├── favicon.ico │ │ ├── logo.png │ │ ├── logo.svg │ │ ├── MCP.png │ │ ├── MCP.svg │ │ └── vite.svg │ ├── README.md │ ├── src │ │ ├── aliyunThemeToken.ts │ │ ├── App.css │ │ ├── App.tsx │ │ ├── assets │ │ │ ├── aliyun.png │ │ │ ├── github.png │ │ │ ├── google.png │ │ │ └── react.svg │ │ ├── components │ │ │ ├── consumer │ │ │ │ ├── ConsumerBasicInfo.tsx │ │ │ │ ├── CredentialManager.tsx │ │ │ │ ├── index.ts │ │ │ │ └── SubscriptionManager.tsx │ │ │ ├── Layout.tsx │ │ │ ├── Navigation.tsx │ │ │ ├── ProductHeader.tsx │ │ │ ├── SwaggerUIWrapper.css │ │ │ ├── SwaggerUIWrapper.tsx │ │ │ └── UserInfo.tsx │ │ ├── index.css │ │ ├── lib │ │ │ ├── api.ts │ │ │ ├── statusUtils.ts │ │ │ └── utils.ts │ │ ├── main.tsx │ │ ├── pages │ │ │ ├── ApiDetail.tsx │ │ │ ├── Apis.tsx │ │ │ ├── Callback.tsx │ │ │ ├── ConsumerDetail.tsx │ │ │ ├── Consumers.tsx │ │ │ ├── GettingStarted.tsx │ │ │ ├── Home.tsx │ │ │ ├── Login.tsx │ │ │ ├── Mcp.tsx │ │ │ ├── McpDetail.tsx │ │ │ ├── OidcCallback.tsx │ │ │ ├── Profile.tsx │ │ │ ├── Register.tsx │ │ │ └── Test.css │ │ ├── router.tsx │ │ ├── types │ │ │ ├── consumer.ts │ │ │ └── index.ts │ │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── README.md ``` # Files -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/PortalDomainRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.PortalDomain; 23 | 24 | import java.util.List; 25 | import java.util.Optional; 26 | 27 | public interface PortalDomainRepository extends BaseRepository<PortalDomain, Long> { 28 | 29 | Optional<PortalDomain> findByDomain(String domain); 30 | 31 | Optional<PortalDomain> findByPortalIdAndDomain(String portalId, String domain); 32 | 33 | List<PortalDomain> findAllByPortalId(String portalId); 34 | 35 | List<PortalDomain> findAllByPortalIdIn(List<String> portalIds); 36 | 37 | void deleteAllByPortalId(String portalId); 38 | } 39 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/NacosResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.entity.NacosInstance; 24 | import lombok.Data; 25 | import java.time.LocalDateTime; 26 | 27 | @Data 28 | public class NacosResult implements OutputConverter<NacosResult, NacosInstance> { 29 | 30 | private String nacosId; 31 | 32 | private String nacosName; 33 | 34 | private String serverUrl; 35 | 36 | 37 | private String username; 38 | 39 | private String accessKey; 40 | 41 | private String description; 42 | 43 | private String adminId; 44 | 45 | private LocalDateTime createAt; 46 | } ``` -------------------------------------------------------------------------------- /portal-bootstrap/src/main/java/com/alibaba/apiopenplatform/PortalApplication.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform; 21 | 22 | import org.springframework.boot.SpringApplication; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; 25 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 26 | import org.springframework.context.annotation.ComponentScan; 27 | 28 | @SpringBootApplication 29 | @EnableJpaAuditing 30 | public class PortalApplication { 31 | 32 | public static void main(String[] args) { 33 | SpringApplication.run(PortalApplication.class, args); 34 | } 35 | } 36 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/consumer/CreateConsumerParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.consumer; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.Consumer; 24 | import lombok.Data; 25 | 26 | import javax.validation.constraints.NotBlank; 27 | import javax.validation.constraints.Size; 28 | 29 | @Data 30 | public class CreateConsumerParam implements InputConverter<Consumer> { 31 | 32 | @NotBlank(message = "Consumer名称不能为空") 33 | @Size(max = 50, message = "Consumer名称长度不能超过50个字符") 34 | private String name; 35 | 36 | @Size(max = 256, message = "Consumer描述长度不能超过256个字符") 37 | private String description; 38 | } 39 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/APIResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.support.enums.GatewayType; 24 | import com.aliyun.sdk.service.apig20240327.models.HttpApiApiInfo; 25 | import lombok.Data; 26 | 27 | @Data 28 | public class APIResult implements OutputConverter<APIResult, HttpApiApiInfo> { 29 | 30 | private String apiId; 31 | 32 | private String apiName; 33 | 34 | @Override 35 | public APIResult convertFrom(HttpApiApiInfo apiInfo) { 36 | setApiId(apiInfo.getHttpApiId()); 37 | setApiName(apiInfo.getName()); 38 | return this; 39 | } 40 | } 41 | ``` -------------------------------------------------------------------------------- /deploy/docker/docker-compose.yml: -------------------------------------------------------------------------------- ```yaml 1 | version: '3' 2 | services: 3 | mysql: 4 | image: opensource-registry.cn-hangzhou.cr.aliyuncs.com/higress-group/mysql:1.0.0 5 | container_name: mysql 6 | environment: 7 | - MYSQL_ROOT_PASSWORD=123456 8 | - MYSQL_DATABASE=portal_db 9 | - MYSQL_USER=portal_user 10 | - MYSQL_PASSWORD=portal_pass 11 | ports: 12 | - "3306:3306" 13 | volumes: 14 | - ./mysql/data:/var/lib/mysql 15 | restart: always 16 | 17 | himarket-server: 18 | image: opensource-registry.cn-hangzhou.cr.aliyuncs.com/higress-group/himarket-server:1.0.0 19 | container_name: himarket-server 20 | environment: 21 | - DB_HOST=mysql 22 | - DB_PORT=3306 23 | - DB_NAME=portal_db 24 | - DB_USERNAME=portal_user 25 | - DB_PASSWORD=portal_pass 26 | ports: 27 | - "8080:8080" 28 | depends_on: 29 | - mysql 30 | restart: always 31 | 32 | himarket-admin: 33 | image: opensource-registry.cn-hangzhou.cr.aliyuncs.com/higress-group/himarket-admin:1.0.0 34 | container_name: himarket-admin 35 | environment: 36 | - HIMARKET_SERVER=http://himarket-server:8080 37 | ports: 38 | - "5174:8000" 39 | depends_on: 40 | - himarket-server 41 | restart: always 42 | 43 | himarket-frontend: 44 | image: opensource-registry.cn-hangzhou.cr.aliyuncs.com/higress-group/himarket-frontend:1.0.0 45 | container_name: himarket-frontend 46 | environment: 47 | - HIMARKET_SERVER=http://himarket-server:8080 48 | ports: 49 | - "5173:8000" 50 | depends_on: 51 | - himarket-server 52 | restart: always ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/core/constant/CommonConstants.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.core.constant; 21 | 22 | public class CommonConstants { 23 | 24 | // Token相关 25 | public static final String AUTHORIZATION_HEADER = "Authorization"; 26 | public static final String BEARER_PREFIX = "Bearer "; 27 | 28 | // 角色前缀 29 | public static final String ROLE_PREFIX = "ROLE_"; 30 | public static final String USER_TYPE = "userType"; 31 | public static final String USER_ID = "userId"; 32 | 33 | // Cookie相关 34 | public static final String AUTH_TOKEN_COOKIE = "auth_token"; 35 | 36 | // HTTP 37 | public static final Integer HTTP_PORT = 80; 38 | public static final Integer HTTPS_PORT = 443; 39 | 40 | } 41 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/consumer/UpdateCredentialParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.consumer; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.ConsumerCredential; 24 | import com.alibaba.apiopenplatform.support.consumer.ApiKeyConfig; 25 | import com.alibaba.apiopenplatform.support.consumer.HmacConfig; 26 | import com.alibaba.apiopenplatform.support.consumer.JwtConfig; 27 | import lombok.Data; 28 | 29 | @Data 30 | public class UpdateCredentialParam implements InputConverter<ConsumerCredential> { 31 | 32 | private ApiKeyConfig apiKeyConfig; 33 | 34 | private HmacConfig hmacConfig; 35 | 36 | private JwtConfig jwtConfig; 37 | } 38 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/src/router.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { Routes, Route } from "react-router-dom"; 2 | import Home from "./pages/Home"; 3 | import Apis from "./pages/Apis"; 4 | import ApiDetail from "./pages/ApiDetail"; 5 | import Consumers from "./pages/Consumers"; 6 | import ConsumerDetail from "./pages/ConsumerDetail"; 7 | import GettingStarted from "./pages/GettingStarted"; 8 | import Mcp from "./pages/Mcp"; 9 | import Login from "./pages/Login"; 10 | import Register from "./pages/Register"; 11 | import Profile from './pages/Profile' 12 | import McpDetail from "./pages/McpDetail"; 13 | import Callback from "./pages/Callback"; 14 | import OidcCallback from "./pages/OidcCallback"; 15 | 16 | export function Router() { 17 | return ( 18 | <Routes> 19 | <Route path="/" element={<Home />} /> 20 | <Route path="/getting-started" element={<GettingStarted />} /> 21 | <Route path="/apis" element={<Apis />} /> 22 | <Route path="/apis/:id" element={<ApiDetail />} /> 23 | <Route path="/consumers/:consumerId" element={<ConsumerDetail />} /> 24 | <Route path="/consumers" element={<Consumers />} /> 25 | <Route path="/mcp" element={<Mcp />} /> 26 | <Route path="/mcp/:mcpName" element={<McpDetail />} /> 27 | <Route path="/login" element={<Login />} /> 28 | <Route path="/register" element={<Register />} /> 29 | <Route path="/profile" element={<Profile />} /> 30 | <Route path="/callback" element={<Callback />} /> 31 | <Route path="/oidc/callback" element={<OidcCallback />} /> 32 | 33 | {/* 其他页面可继续添加 */} 34 | </Routes> 35 | ); 36 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/converter/OutputConverter.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.converter; 21 | 22 | import cn.hutool.core.bean.BeanUtil; 23 | import cn.hutool.core.bean.copier.CopyOptions; 24 | 25 | public interface OutputConverter<Target extends OutputConverter<Target, Source>, Source> { 26 | 27 | /** 28 | * 以Source更新Target 29 | * 30 | * @param source 31 | * @return 32 | */ 33 | @SuppressWarnings("unchecked") 34 | default Target convertFrom(Source source) { 35 | BeanUtil.copyProperties(source, this, configOptions()); 36 | return (Target) this; 37 | } 38 | 39 | default CopyOptions configOptions() { 40 | return CopyOptions.create().ignoreNullValue().ignoreError(); 41 | } 42 | } 43 | 44 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/src/routes/index.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { createBrowserRouter, Navigate } from 'react-router-dom'; 2 | import LayoutWrapper from '@/components/LayoutWrapper'; 3 | import Portals from '@/pages/Portals'; 4 | import ApiProducts from '@/pages/ApiProducts'; 5 | import GatewayConsoles from '@/pages/GatewayConsoles'; 6 | import NacosConsoles from '@/pages/NacosConsoles'; 7 | import PortalDetail from '@/pages/PortalDetail'; 8 | import ApiProductDetail from '@/pages/ApiProductDetail'; 9 | import Login from '@/pages/Login'; 10 | 11 | export const router = createBrowserRouter([ 12 | { 13 | path: '/login', 14 | element: <Login />, 15 | }, 16 | { 17 | path: '/', 18 | element: <LayoutWrapper />, 19 | children: [ 20 | { 21 | index: true, 22 | element: <Navigate to="/portals" replace />, 23 | }, 24 | { 25 | path: 'portals', 26 | element: <Portals />, 27 | }, 28 | { 29 | path: 'portals/detail', 30 | element: <PortalDetail />, 31 | }, 32 | { 33 | path: 'api-products', 34 | element: <ApiProducts />, 35 | }, 36 | { 37 | path: 'api-products/detail', 38 | element: <ApiProductDetail />, 39 | }, 40 | { 41 | path: 'consoles', 42 | element: <Navigate to="/consoles/gateway" replace />, 43 | }, 44 | { 45 | path: 'consoles/gateway', 46 | element: <GatewayConsoles />, 47 | }, 48 | { 49 | path: 'consoles/nacos', 50 | element: <NacosConsoles />, 51 | }, 52 | { 53 | path: '*', 54 | element: <Navigate to="/portals" replace />, 55 | }, 56 | ], 57 | }, 58 | ]); 59 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/ConsumerCredentialResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.entity.ConsumerCredential; 24 | import com.alibaba.apiopenplatform.support.consumer.ApiKeyConfig; 25 | import com.alibaba.apiopenplatform.support.consumer.HmacConfig; 26 | import com.alibaba.apiopenplatform.support.consumer.JwtConfig; 27 | import lombok.Data; 28 | 29 | @Data 30 | public class ConsumerCredentialResult implements OutputConverter<ConsumerCredentialResult, ConsumerCredential> { 31 | 32 | private JwtConfig jwtConfig; 33 | 34 | private HmacConfig hmacConfig; 35 | 36 | private ApiKeyConfig apiKeyConfig; 37 | } 38 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/portal/CreatePortalParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.portal; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.Portal; 24 | import io.swagger.v3.oas.annotations.media.Schema; 25 | import lombok.Data; 26 | 27 | import javax.validation.constraints.NotBlank; 28 | import javax.validation.constraints.Size; 29 | 30 | @Schema(description = "创建门户参数") 31 | @Data 32 | public class CreatePortalParam implements InputConverter<Portal> { 33 | 34 | @NotBlank(message = "门户名称不能为空") 35 | @Size(max = 50, message = "门户名称长度不能超过50个字符") 36 | private String name; 37 | 38 | @Size(max = 1024, message = "门户描述长度不能超过1024个字符") 39 | private String description; 40 | } 41 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/src/types/consumer.ts: -------------------------------------------------------------------------------- ```typescript 1 | import type { Product } from "./index"; 2 | 3 | export interface Consumer { 4 | consumerId: string; 5 | name: string; 6 | description?: string; 7 | status?: string; 8 | createAt?: string; 9 | enabled?: boolean; 10 | } 11 | 12 | export type ConsumerCredential = HMACCredential | APIKeyCredential; 13 | 14 | export interface HMACCredential { 15 | ak?: string; 16 | sk?: string; 17 | mode?: 'SYSTEM' | 'CUSTOM'; 18 | } 19 | 20 | export interface APIKeyCredential { 21 | apiKey?: string; 22 | mode?: 'SYSTEM' | 'CUSTOM'; 23 | } 24 | 25 | export interface ConsumerCredentialResult { 26 | apiKeyConfig?: { 27 | credentials?: Array<{ 28 | apiKey?: string; 29 | mode?: 'SYSTEM' | 'CUSTOM'; 30 | }>; 31 | source?: string; 32 | key?: string; 33 | }; 34 | hmacConfig?: { 35 | credentials?: Array<{ 36 | ak?: string; 37 | sk?: string; 38 | mode?: 'SYSTEM' | 'CUSTOM'; 39 | }>; 40 | }; 41 | jwtConfig?: Record<string, unknown>; 42 | } 43 | 44 | export interface Subscription { 45 | productId: string; 46 | consumerId: string; 47 | status: 'PENDING' | 'APPROVED'; 48 | createAt: string; 49 | updatedAt: string; 50 | productName: string; 51 | productType: 'REST_API' | 'MCP_SERVER'; 52 | consumerName?: string; 53 | product?: Product; 54 | } 55 | 56 | export interface CreateCredentialParam { 57 | apiKeyConfig?: { 58 | credentials?: Array<{ 59 | apiKey?: string; 60 | mode?: 'SYSTEM' | 'CUSTOM'; 61 | }>; 62 | source?: string; 63 | key?: string; 64 | }; 65 | hmacConfig?: { 66 | credentials?: Array<{ 67 | ak?: string; 68 | sk?: string; 69 | mode?: 'SYSTEM' | 'CUSTOM'; 70 | }>; 71 | }; 72 | jwtConfig?: Record<string, unknown>; 73 | } ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "portal-frontend", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview", 11 | "prepare": "husky", 12 | "serve": "npm run build && npm start", 13 | "type-check": "tsc -b" 14 | }, 15 | "dependencies": { 16 | "@ant-design/icons": "^5.2.7", 17 | "antd": "^5.15.8", 18 | "axios": "^1.10.0", 19 | "clsx": "^2.1.1", 20 | "js-yaml": "^4.1.0", 21 | "monaco-editor": "^0.52.2", 22 | "postcss": "^8.5.6", 23 | "react": "^18.0.0", 24 | "react-dom": "^18.0.0", 25 | "react-markdown": "^10.1.0", 26 | "react-markdown-editor-lite": "^1.3.4", 27 | "react-monaco-editor": "^0.59.0", 28 | "react-router-dom": "^6.23.1", 29 | "remark-gfm": "^4.0.1", 30 | "swagger-ui-react": "^5.29.0", 31 | "terser": "^5.43.1" 32 | }, 33 | "devDependencies": { 34 | "@eslint/js": "^9.30.1", 35 | "@types/js-yaml": "^4.0.9", 36 | "@types/node": "^24.3.0", 37 | "@types/react": "^18.3.3", 38 | "@types/react-dom": "^18.3.3", 39 | "@types/swagger-ui-react": "^5.18.0", 40 | "@vitejs/plugin-react": "^4.6.0", 41 | "autoprefixer": "^10.4.19", 42 | "compression": "^1.8.1", 43 | "eslint": "^9.30.1", 44 | "eslint-plugin-react-hooks": "^5.2.0", 45 | "eslint-plugin-react-refresh": "^0.4.20", 46 | "globals": "^16.3.0", 47 | "husky": "^9.1.7", 48 | "postcss": "^8.5.6", 49 | "tailwindcss": "^3.4.3", 50 | "typescript": "~5.8.3", 51 | "typescript-eslint": "^8.35.1", 52 | "vite": "^4.5.14" 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/src/index.css: -------------------------------------------------------------------------------- ```css 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --radius: 0.625rem; 7 | --background: oklch(1 0 0); 8 | --foreground: oklch(0.145 0 0); 9 | --card: oklch(1 0 0); 10 | --card-foreground: oklch(0.145 0 0); 11 | --popover: oklch(1 0 0); 12 | --popover-foreground: oklch(0.145 0 0); 13 | --primary: oklch(0.205 0 0); 14 | --primary-foreground: oklch(0.985 0 0); 15 | --secondary: oklch(0.97 0 0); 16 | --secondary-foreground: oklch(0.205 0 0); 17 | --muted: oklch(0.97 0 0); 18 | --muted-foreground: oklch(0.556 0 0); 19 | --accent: oklch(0.97 0 0); 20 | --accent-foreground: oklch(0.205 0 0); 21 | --destructive: oklch(0.577 0.245 27.325); 22 | --border: oklch(0.922 0 0); 23 | --input: oklch(0.922 0 0); 24 | --ring: oklch(0.708 0 0); 25 | } 26 | 27 | .dark { 28 | --background: oklch(0.145 0 0); 29 | --foreground: oklch(0.985 0 0); 30 | --card: oklch(0.205 0 0); 31 | --card-foreground: oklch(0.985 0 0); 32 | --popover: oklch(0.205 0 0); 33 | --popover-foreground: oklch(0.985 0 0); 34 | --primary: oklch(0.922 0 0); 35 | --primary-foreground: oklch(0.205 0 0); 36 | --secondary: oklch(0.269 0 0); 37 | --secondary-foreground: oklch(0.985 0 0); 38 | --muted: oklch(0.269 0 0); 39 | --muted-foreground: oklch(0.708 0 0); 40 | --accent: oklch(0.269 0 0); 41 | --accent-foreground: oklch(0.985 0 0); 42 | --destructive: oklch(0.704 0.191 22.216); 43 | --border: oklch(1 0 0 / 10%); 44 | --input: oklch(1 0 0 / 15%); 45 | --ring: oklch(0.556 0 0); 46 | } 47 | 48 | @layer base { 49 | * { 50 | @apply border-gray-200; 51 | } 52 | body { 53 | @apply bg-white text-gray-900; 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/src/index.css: -------------------------------------------------------------------------------- ```css 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --radius: 0.625rem; 7 | --background: oklch(1 0 0); 8 | --foreground: oklch(0.145 0 0); 9 | --card: oklch(1 0 0); 10 | --card-foreground: oklch(0.145 0 0); 11 | --popover: oklch(1 0 0); 12 | --popover-foreground: oklch(0.145 0 0); 13 | --primary: oklch(0.205 0 0); 14 | --primary-foreground: oklch(0.985 0 0); 15 | --secondary: oklch(0.97 0 0); 16 | --secondary-foreground: oklch(0.205 0 0); 17 | --muted: oklch(0.97 0 0); 18 | --muted-foreground: oklch(0.556 0 0); 19 | --accent: oklch(0.97 0 0); 20 | --accent-foreground: oklch(0.205 0 0); 21 | --destructive: oklch(0.577 0.245 27.325); 22 | --border: oklch(0.922 0 0); 23 | --input: oklch(0.922 0 0); 24 | --ring: oklch(0.708 0 0); 25 | } 26 | 27 | .dark { 28 | --background: oklch(0.145 0 0); 29 | --foreground: oklch(0.985 0 0); 30 | --card: oklch(0.205 0 0); 31 | --card-foreground: oklch(0.985 0 0); 32 | --popover: oklch(0.205 0 0); 33 | --popover-foreground: oklch(0.985 0 0); 34 | --primary: oklch(0.922 0 0); 35 | --primary-foreground: oklch(0.205 0 0); 36 | --secondary: oklch(0.269 0 0); 37 | --secondary-foreground: oklch(0.985 0 0); 38 | --muted: oklch(0.269 0 0); 39 | --muted-foreground: oklch(0.708 0 0); 40 | --accent: oklch(0.269 0 0); 41 | --accent-foreground: oklch(0.985 0 0); 42 | --destructive: oklch(0.704 0.191 22.216); 43 | --border: oklch(1 0 0 / 10%); 44 | --input: oklch(1 0 0 / 15%); 45 | --ring: oklch(0.556 0 0); 46 | } 47 | 48 | @layer base { 49 | * { 50 | @apply border-gray-200; 51 | } 52 | body { 53 | @apply bg-white text-gray-900; 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/HigressMCPServerResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.service.gateway.HigressOperator.HigressMCPConfig; 24 | import lombok.Data; 25 | import lombok.EqualsAndHashCode; 26 | 27 | @EqualsAndHashCode(callSuper = true) 28 | @Data 29 | public class HigressMCPServerResult extends GatewayMCPServerResult implements OutputConverter<HigressMCPServerResult, HigressMCPConfig> { 30 | 31 | @Override 32 | public HigressMCPServerResult convertFrom(HigressMCPConfig mcp) { 33 | HigressMCPServerResult r = OutputConverter.super.convertFrom(mcp); 34 | r.setMcpServerName(mcp.getName()); 35 | return r; 36 | } 37 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/PortalRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.Portal; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | 26 | import java.util.Optional; 27 | 28 | public interface PortalRepository extends BaseRepository<Portal, Long> { 29 | 30 | Optional<Portal> findFirstByOrderByIdAsc(); 31 | 32 | Optional<Portal> findByPortalIdAndAdminId(String portalId, String adminId); 33 | 34 | Optional<Portal> findByPortalId(String portalId); 35 | 36 | Optional<Portal> findByNameAndAdminId(String name, String adminId); 37 | 38 | Optional<Portal> findByName(String name); 39 | 40 | Page<Portal> findByAdminId(String adminId, Pageable pageable); 41 | } 42 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/SubscriptionResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.entity.ProductSubscription; 24 | import com.alibaba.apiopenplatform.support.enums.ProductType; 25 | import lombok.Data; 26 | 27 | import java.time.LocalDateTime; 28 | 29 | @Data 30 | public class SubscriptionResult implements OutputConverter<SubscriptionResult, ProductSubscription> { 31 | 32 | private String productId; 33 | 34 | private String consumerId; 35 | 36 | private String status; 37 | 38 | private ProductType productType; 39 | 40 | private String productName; 41 | 42 | private String consumerName; 43 | 44 | private LocalDateTime createAt; 45 | 46 | private LocalDateTime updatedAt; 47 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/support/portal/OidcConfig.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.support.portal; 21 | 22 | import com.alibaba.apiopenplatform.support.enums.GrantType; 23 | import lombok.Data; 24 | 25 | @Data 26 | public class OidcConfig { 27 | /** 28 | * 提供商 29 | */ 30 | private String provider; 31 | 32 | /** 33 | * 对外的名称 34 | */ 35 | private String name; 36 | 37 | /** 38 | * 登录按钮logo 39 | */ 40 | private String logoUrl; 41 | 42 | /** 43 | * 是否启用 44 | */ 45 | private boolean enabled = true; 46 | 47 | /** 48 | * 授权类型,默认授权码 49 | */ 50 | private GrantType grantType = GrantType.AUTHORIZATION_CODE; 51 | 52 | /** 53 | * 授权码模式配置 54 | */ 55 | private AuthCodeConfig authCodeConfig; 56 | 57 | /** 58 | * 身份映射 59 | */ 60 | private IdentityMapping identityMapping = new IdentityMapping(); 61 | } 62 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/portal/BindDomainParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.portal; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.PortalDomain; 24 | import com.alibaba.apiopenplatform.support.enums.DomainType; 25 | import com.alibaba.apiopenplatform.support.enums.ProtocolType; 26 | import lombok.Data; 27 | 28 | import javax.validation.constraints.NotBlank; 29 | import javax.validation.constraints.NotNull; 30 | 31 | @Data 32 | public class BindDomainParam implements InputConverter<PortalDomain> { 33 | 34 | @NotBlank(message = "门户域名不能为空") 35 | private String domain; 36 | 37 | @NotNull(message = "域名协议不能为空") 38 | private ProtocolType protocol; 39 | 40 | private DomainType type = DomainType.CUSTOM; 41 | } 42 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/SubscriptionRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.ProductSubscription; 23 | 24 | import java.util.List; 25 | import java.util.Optional; 26 | 27 | public interface SubscriptionRepository extends BaseRepository<ProductSubscription, Long> { 28 | 29 | Optional<ProductSubscription> findByConsumerIdAndProductId(String consumerId, String productId); 30 | 31 | List<ProductSubscription> findALlByConsumerId(String consumerId); 32 | 33 | List<ProductSubscription> findAllByProductId(String productId); 34 | 35 | void deleteAllByConsumerId(String consumerId); 36 | 37 | void deleteAllByProductId(String productId); 38 | 39 | void deleteByConsumerIdAndProductId(String consumerId, String productId); 40 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/core/response/Response.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.core.response; 21 | 22 | import lombok.Data; 23 | import lombok.experimental.Accessors; 24 | import lombok.NoArgsConstructor; 25 | import lombok.AllArgsConstructor; 26 | 27 | @Data 28 | @Accessors(chain = true) 29 | @NoArgsConstructor 30 | @AllArgsConstructor 31 | public class Response<T> { 32 | private String code; 33 | private String message; 34 | private T data; 35 | 36 | public static <T> Response<T> ok(T data) { 37 | return new Response<T>() 38 | .setCode("SUCCESS") 39 | .setData(data); 40 | } 41 | 42 | public static <T> Response<T> fail(String code, String message) { 43 | return new Response<T>() 44 | .setCode(code) 45 | .setMessage(message); 46 | } 47 | } 48 | 49 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/public/vite.svg: -------------------------------------------------------------------------------- ``` 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/public/vite.svg: -------------------------------------------------------------------------------- ``` 1 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg> ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/nacos/QueryNacosParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.nacos; 21 | 22 | import lombok.Data; 23 | 24 | import javax.validation.constraints.NotBlank; 25 | 26 | import com.aliyun.teaopenapi.models.Config; 27 | 28 | /** 29 | * 查询Nacos集群参数 30 | * 31 | */ 32 | @Data 33 | public class QueryNacosParam { 34 | 35 | @NotBlank(message = "地域不能为空") 36 | private String regionId; 37 | 38 | @NotBlank(message = "accessKey不能为空") 39 | private String accessKey; 40 | 41 | @NotBlank(message = "secretKey不能为空") 42 | private String secretKey; 43 | 44 | public Config toClientConfig() { 45 | Config config = new Config() 46 | .setAccessKeyId(this.accessKey) 47 | .setAccessKeySecret(this.secretKey) 48 | .setRegionId(this.regionId); 49 | return config; 50 | } 51 | } 52 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/service/gateway/client/GatewayClient.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.service.gateway.client; 21 | 22 | import java.net.InetSocketAddress; 23 | import java.net.Socket; 24 | 25 | public abstract class GatewayClient { 26 | 27 | public void close() { 28 | 29 | } 30 | 31 | protected String getAPIGEndpoint(String region) { 32 | String internalEndpoint = String.format("apig-vpc.%s.aliyuncs.com", region); 33 | String publicEndpoint = String.format("apig.%s.aliyuncs.com", region); 34 | 35 | // 优先尝试内网endpoint 36 | try (Socket socket = new Socket()) { 37 | socket.connect(new InetSocketAddress(internalEndpoint, 443), 1000); // 1秒超时 38 | return internalEndpoint; 39 | } catch (Exception e) { 40 | return publicEndpoint; 41 | } 42 | } 43 | } 44 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/NacosMCPServerResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.nacos.api.ai.model.mcp.McpServerBasicInfo; 24 | import lombok.Data; 25 | import lombok.EqualsAndHashCode; 26 | 27 | @Data 28 | @EqualsAndHashCode(callSuper = true) 29 | public class NacosMCPServerResult extends MCPServerResult implements OutputConverter<NacosMCPServerResult, McpServerBasicInfo> { 30 | 31 | private String version; 32 | 33 | @Override 34 | public NacosMCPServerResult convertFrom(McpServerBasicInfo basicInfo) { 35 | OutputConverter.super.convertFrom(basicInfo); 36 | setMcpServerName(basicInfo.getName()); 37 | setVersion(basicInfo.getVersion()); 38 | return this; 39 | } 40 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/DeveloperExternalIdentityRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.DeveloperExternalIdentity; 23 | import org.springframework.data.jpa.repository.JpaRepository; 24 | import java.util.List; 25 | import java.util.Optional; 26 | 27 | public interface DeveloperExternalIdentityRepository extends JpaRepository<DeveloperExternalIdentity, Long> { 28 | 29 | List<DeveloperExternalIdentity> findByDeveloper_DeveloperId(String developerId); 30 | 31 | Optional<DeveloperExternalIdentity> findByProviderAndSubject(String provider, String subject); 32 | 33 | void deleteByProviderAndSubjectAndDeveloper_DeveloperId(String provider, String subject, String developerId); 34 | 35 | void deleteByDeveloper_DeveloperId(String developerId); 36 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/portal/UpdatePortalParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.portal; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.Portal; 24 | import com.alibaba.apiopenplatform.support.portal.PortalSettingConfig; 25 | import com.alibaba.apiopenplatform.support.portal.PortalUiConfig; 26 | import lombok.Data; 27 | 28 | import javax.validation.constraints.Size; 29 | 30 | @Data 31 | public class UpdatePortalParam implements InputConverter<Portal> { 32 | 33 | @Size(max = 50, message = "门户名称长度不能超过50个字符") 34 | private String name; 35 | 36 | @Size(max = 1024, message = "门户描述长度不能超过1024个字符") 37 | private String description; 38 | 39 | private PortalSettingConfig portalSettingConfig; 40 | 41 | private PortalUiConfig portalUiConfig; 42 | } 43 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/gateway/QueryAPIGParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.gateway; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.support.enums.GatewayType; 24 | import com.alibaba.apiopenplatform.support.gateway.APIGConfig; 25 | import lombok.Data; 26 | 27 | import javax.validation.constraints.NotBlank; 28 | import javax.validation.constraints.NotNull; 29 | 30 | @Data 31 | public class QueryAPIGParam implements InputConverter<APIGConfig> { 32 | 33 | @NotBlank(message = "网关region不能为空") 34 | private String region; 35 | 36 | @NotNull(message = "网关类型不能为空") 37 | private GatewayType gatewayType; 38 | 39 | @NotBlank(message = "accessKey不能为空") 40 | private String accessKey; 41 | 42 | @NotBlank(message = "secretKey不能为空") 43 | private String secretKey; 44 | } 45 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/developer/CreateDeveloperParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.developer; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.Developer; 24 | import lombok.Data; 25 | import lombok.NoArgsConstructor; 26 | 27 | import javax.validation.constraints.NotBlank; 28 | import javax.validation.constraints.Size; 29 | 30 | @Data 31 | @NoArgsConstructor 32 | public class CreateDeveloperParam implements InputConverter<Developer> { 33 | 34 | @NotBlank(message = "用户名不能为空") 35 | @Size(max = 64, message = "用户名长度不能超过64个字符") 36 | private String username; 37 | 38 | @NotBlank(message = "密码不能为空") 39 | @Size(min = 6, max = 32, message = "密码长度应为6-32位") 40 | private String password; 41 | 42 | @Size(max = 256, message = "头像url长度不能超过256个字符") 43 | private String avatarUrl; 44 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/BaseEntity.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import lombok.Data; 23 | import org.springframework.data.annotation.CreatedDate; 24 | import org.springframework.data.annotation.LastModifiedDate; 25 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 26 | 27 | import javax.persistence.*; 28 | import java.io.Serializable; 29 | import java.time.LocalDateTime; 30 | 31 | @MappedSuperclass 32 | @EntityListeners(AuditingEntityListener.class) 33 | @Data 34 | public class BaseEntity implements Serializable { 35 | 36 | @CreatedDate 37 | @Column(name = "created_at", updatable = false, columnDefinition = "datetime(3)") 38 | private LocalDateTime createAt; 39 | 40 | @LastModifiedDate 41 | @Column(name = "updated_at", columnDefinition = "datetime(3)") 42 | private LocalDateTime updatedAt; 43 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/ProductPublicationRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.ProductPublication; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | 26 | import java.util.Optional; 27 | 28 | public interface ProductPublicationRepository extends BaseRepository<ProductPublication, Long> { 29 | 30 | Page<ProductPublication> findByPortalId(String portalId, Pageable pageable); 31 | 32 | Optional<ProductPublication> findByPortalIdAndProductId(String portalId, String productId); 33 | 34 | Page<ProductPublication> findByProductId(String productId, Pageable pageable); 35 | 36 | void deleteByProductId(String productId); 37 | 38 | void deleteAllByPortalId(String portalId); 39 | 40 | boolean existsByProductId(String productId); 41 | } 42 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/ProductRefRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.ProductRef; 23 | import com.alibaba.apiopenplatform.support.enums.SourceType; 24 | import org.springframework.data.jpa.repository.JpaRepository; 25 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 26 | import org.springframework.stereotype.Repository; 27 | 28 | import java.util.List; 29 | import java.util.Optional; 30 | 31 | /** 32 | * API Reference Repository 33 | */ 34 | @Repository 35 | public interface ProductRefRepository extends JpaRepository<ProductRef, Long>, JpaSpecificationExecutor<ProductRef> { 36 | 37 | Optional<ProductRef> findByProductId(String productId); 38 | 39 | Optional<ProductRef> findFirstByProductId(String productId); 40 | 41 | boolean existsByGatewayId(String gatewayId); 42 | } 43 | ``` -------------------------------------------------------------------------------- /portal-dal/pom.xml: -------------------------------------------------------------------------------- ``` 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | <parent> 7 | <groupId>com.alibaba.himarket</groupId> 8 | <artifactId>himarket</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | </parent> 11 | 12 | <artifactId>portal-dal</artifactId> 13 | 14 | <properties> 15 | <maven.compiler.source>8</maven.compiler.source> 16 | <maven.compiler.target>8</maven.compiler.target> 17 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 18 | </properties> 19 | 20 | <dependencies> 21 | <dependency> 22 | <groupId>org.springframework.boot</groupId> 23 | <artifactId>spring-boot-starter-data-jpa</artifactId> 24 | </dependency> 25 | 26 | <dependency> 27 | <groupId>org.mariadb.jdbc</groupId> 28 | <artifactId>mariadb-java-client</artifactId> 29 | </dependency> 30 | 31 | <dependency> 32 | <groupId>org.projectlombok</groupId> 33 | <artifactId>lombok</artifactId> 34 | </dependency> 35 | 36 | <dependency> 37 | <groupId>cn.hutool</groupId> 38 | <artifactId>hutool-all</artifactId> 39 | </dependency> 40 | 41 | <dependency> 42 | <groupId>com.fasterxml.jackson.core</groupId> 43 | <artifactId>jackson-databind</artifactId> 44 | <version>2.14.0-rc1</version> 45 | </dependency> 46 | </dependencies> 47 | 48 | </project> ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/AuthResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import cn.hutool.core.annotation.Alias; 23 | import com.fasterxml.jackson.annotation.JsonProperty; 24 | import lombok.Builder; 25 | import lombok.Data; 26 | 27 | @Data 28 | @Builder 29 | public class AuthResult { 30 | 31 | @Alias("access_token") 32 | @JsonProperty("access_token") 33 | private String accessToken; 34 | 35 | @Alias("token_type") 36 | @JsonProperty("token_type") 37 | @Builder.Default 38 | private String tokenType = "Bearer"; 39 | 40 | @Alias("expires_in") 41 | @JsonProperty("expires_in") 42 | private Long expiresIn; 43 | 44 | public static AuthResult of(String accessToken, Long expiresIn) { 45 | return AuthResult.builder() 46 | .accessToken(accessToken) 47 | .expiresIn(expiresIn) 48 | .build(); 49 | } 50 | } ``` -------------------------------------------------------------------------------- /deploy/helm/templates/himarket-admin-deployment.yaml: -------------------------------------------------------------------------------- ```yaml 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: himarket-admin 5 | labels: 6 | app: himarket-admin 7 | spec: 8 | replicas: {{ .Values.admin.replicaCount }} 9 | selector: 10 | matchLabels: 11 | app: himarket-admin 12 | template: 13 | metadata: 14 | labels: 15 | app: himarket-admin 16 | spec: 17 | {{- with .Values.imagePullSecrets }} 18 | imagePullSecrets: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | serviceAccountName: {{ include "himarket.serviceAccountName" . }} 22 | containers: 23 | - name: admin 24 | image: "{{ .Values.hub }}/{{ .Values.admin.image.repository }}:{{ .Values.admin.image.tag}}" 25 | imagePullPolicy: {{ .Values.admin.image.pullPolicy }} 26 | ports: 27 | - name: http 28 | containerPort: {{ .Values.admin.serverPort }} 29 | protocol: TCP 30 | envFrom: 31 | - configMapRef: 32 | name: himarket-admin 33 | {{- with .Values.resources }} 34 | resources: 35 | {{- toYaml . | nindent 12 }} 36 | {{- end }} 37 | {{- with .Values.volumeMounts }} 38 | volumeMounts: 39 | {{- toYaml . | nindent 12 }} 40 | {{- end }} 41 | {{- with .Values.volumes }} 42 | volumes: 43 | {{- toYaml . | nindent 8 }} 44 | {{- end }} 45 | {{- with .Values.nodeSelector }} 46 | nodeSelector: 47 | {{- toYaml . | nindent 8 }} 48 | {{- end }} 49 | {{- with .Values.affinity }} 50 | affinity: 51 | {{- toYaml . | nindent 8 }} 52 | {{- end }} 53 | {{- with .Values.tolerations }} 54 | tolerations: 55 | {{- toYaml . | nindent 8 }} 56 | {{- end }} 57 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/APIGMCPServerResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.aliyun.sdk.service.apig20240327.models.HttpRoute; 24 | import lombok.Data; 25 | import lombok.EqualsAndHashCode; 26 | 27 | @EqualsAndHashCode(callSuper = true) 28 | @Data 29 | public class APIGMCPServerResult extends GatewayMCPServerResult implements OutputConverter<APIGMCPServerResult, HttpRoute> { 30 | 31 | private String apiId; 32 | 33 | private String mcpServerId; 34 | 35 | private String mcpRouteId; 36 | 37 | @Override 38 | public APIGMCPServerResult convertFrom(HttpRoute httpRoute) { 39 | APIGMCPServerResult r = OutputConverter.super.convertFrom(httpRoute); 40 | r.setMcpServerName(httpRoute.getName()); 41 | r.setMcpRouteId(httpRoute.getRouteId()); 42 | return r; 43 | } 44 | } 45 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "portal-admin", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview", 11 | "start": "node server.js", 12 | "serve": "npm run build && npm start", 13 | "serve-live": "npx live-server dist --port=3000 --entry-file=index.html" 14 | }, 15 | "dependencies": { 16 | "@babel/runtime": "^8.0.0-alpha.17", 17 | "antd": "^5.15.7", 18 | "axios": "^1.7.9", 19 | "clsx": "^2.1.1", 20 | "helmet": "^7.1.0", 21 | "js-yaml": "^4.1.0", 22 | "monaco-editor": "^0.52.2", 23 | "postcss": "^8.5.6", 24 | "react": "^18.0.0", 25 | "react-dom": "^18.0.0", 26 | "react-markdown": "^10.1.0", 27 | "react-markdown-editor-lite": "^1.3.4", 28 | "react-monaco-editor": "^0.59.0", 29 | "react-router-dom": "^6.28.0", 30 | "remark-gfm": "^4.0.1", 31 | "swagger-ui-react": "^5.29.0", 32 | "tailwind-merge": "^3.3.1", 33 | "terser": "^5.43.1" 34 | }, 35 | "resolutions": { 36 | "@babel/runtime": "^8.0.0-alpha.17" 37 | }, 38 | "devDependencies": { 39 | "@eslint/js": "^9.30.1", 40 | "@types/js-yaml": "^4.0.9", 41 | "@types/node": "^24.3.0", 42 | "@types/react": "^18.3.3", 43 | "@types/react-dom": "^18.3.3", 44 | "@vitejs/plugin-react": "^4.7.0", 45 | "autoprefixer": "^10.4.21", 46 | "compression": "^1.8.0", 47 | "cors": "^2.8.5", 48 | "eslint": "^9.30.1", 49 | "eslint-plugin-react-hooks": "^5.2.0", 50 | "eslint-plugin-react-refresh": "^0.4.20", 51 | "express": "^4.21.2", 52 | "globals": "^16.3.0", 53 | "path": "^0.12.7", 54 | "postcss": "^8.5.6", 55 | "tailwindcss": "^3.4.17", 56 | "typescript": "^5.6.3", 57 | "url": "^0.11.4", 58 | "vite": "^4.5.14" 59 | } 60 | } 61 | ``` -------------------------------------------------------------------------------- /deploy/helm/templates/himarket-frontend-deployment.yaml: -------------------------------------------------------------------------------- ```yaml 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: himarket-frontend 5 | labels: 6 | app: himarket-frontend 7 | spec: 8 | replicas: {{ .Values.frontend.replicaCount }} 9 | selector: 10 | matchLabels: 11 | app: himarket-frontend 12 | template: 13 | metadata: 14 | labels: 15 | app: himarket-frontend 16 | spec: 17 | {{- with .Values.imagePullSecrets }} 18 | imagePullSecrets: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | serviceAccountName: {{ include "himarket.serviceAccountName" . }} 22 | containers: 23 | - name: frontend 24 | image: "{{ .Values.hub }}/{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag}}" 25 | imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} 26 | ports: 27 | - name: http 28 | containerPort: {{ .Values.frontend.serverPort }} 29 | protocol: TCP 30 | envFrom: 31 | - configMapRef: 32 | name: himarket-frontend 33 | {{- with .Values.resources }} 34 | resources: 35 | {{- toYaml . | nindent 12 }} 36 | {{- end }} 37 | {{- with .Values.volumeMounts }} 38 | volumeMounts: 39 | {{- toYaml . | nindent 12 }} 40 | {{- end }} 41 | {{- with .Values.volumes }} 42 | volumes: 43 | {{- toYaml . | nindent 8 }} 44 | {{- end }} 45 | {{- with .Values.nodeSelector }} 46 | nodeSelector: 47 | {{- toYaml . | nindent 8 }} 48 | {{- end }} 49 | {{- with .Values.affinity }} 50 | affinity: 51 | {{- toYaml . | nindent 8 }} 52 | {{- end }} 53 | {{- with .Values.tolerations }} 54 | tolerations: 55 | {{- toYaml . | nindent 8 }} 56 | {{- end }} 57 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/consumer/CreateCredentialParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.consumer; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.ConsumerCredential; 24 | import com.alibaba.apiopenplatform.support.consumer.ApiKeyConfig; 25 | import com.alibaba.apiopenplatform.support.consumer.HmacConfig; 26 | import com.alibaba.apiopenplatform.support.consumer.JwtConfig; 27 | import lombok.Data; 28 | 29 | import javax.validation.constraints.AssertTrue; 30 | 31 | @Data 32 | public class CreateCredentialParam implements InputConverter<ConsumerCredential> { 33 | 34 | private ApiKeyConfig apiKeyConfig; 35 | 36 | private HmacConfig hmacConfig; 37 | 38 | private JwtConfig jwtConfig; 39 | 40 | @AssertTrue(message = "凭证信息不能为空") 41 | private boolean isValid() { 42 | return apiKeyConfig != null || hmacConfig != null || jwtConfig != null; 43 | } 44 | } 45 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/nacos/CreateNacosParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.nacos; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 23 | import com.alibaba.apiopenplatform.entity.NacosInstance; 24 | 25 | import lombok.Data; 26 | 27 | import javax.validation.constraints.NotBlank; 28 | 29 | /** 30 | * 创建Nacos实例参数 31 | * 32 | */ 33 | @Data 34 | public class CreateNacosParam implements InputConverter<NacosInstance> { 35 | 36 | @NotBlank(message = "Nacos名称不能为空") 37 | private String nacosName; 38 | 39 | @NotBlank(message = "服务器地址不能为空") 40 | private String serverUrl; 41 | 42 | /** 43 | * 可选:客户端指定的 nacosId,若为空则由服务端生成 44 | */ 45 | private String nacosId; 46 | 47 | // namespace removed from create param as it's no longer stored on instance 48 | 49 | private String username; 50 | 51 | private String password; 52 | 53 | private String accessKey; 54 | 55 | private String secretKey; 56 | 57 | private String description; 58 | } 59 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/support/enums/GatewayType.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.support.enums; 21 | 22 | import lombok.Getter; 23 | import lombok.RequiredArgsConstructor; 24 | 25 | @RequiredArgsConstructor 26 | @Getter 27 | public enum GatewayType { 28 | 29 | /** 30 | * 云原生API网关 31 | */ 32 | APIG_API("API"), 33 | 34 | /** 35 | * AI网关 36 | */ 37 | APIG_AI("AI"), 38 | 39 | /** 40 | * ADP AI网关 41 | */ 42 | ADP_AI_GATEWAY("ADP_AI_GATEWAY"), 43 | 44 | /** 45 | * Higress 46 | */ 47 | HIGRESS("Higress"), 48 | 49 | ; 50 | 51 | private final String type; 52 | 53 | public boolean isHigress() { 54 | return this == HIGRESS; 55 | } 56 | 57 | public boolean isAPIG() { 58 | return this == APIG_API || this == APIG_AI || this == ADP_AI_GATEWAY; 59 | } 60 | 61 | public boolean isAIGateway() { 62 | return this == APIG_AI || this == ADP_AI_GATEWAY; 63 | } 64 | 65 | public boolean isAdpAIGateway() { 66 | return this == ADP_AI_GATEWAY; 67 | } 68 | } 69 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/BaseRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.ProductPublication; 23 | import org.springframework.data.domain.Sort; 24 | import org.springframework.data.jpa.repository.JpaRepository; 25 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 26 | import org.springframework.data.repository.NoRepositoryBean; 27 | import org.springframework.lang.NonNull; 28 | 29 | import java.util.Collection; 30 | import java.util.List; 31 | 32 | /** 33 | * 基础数据访问接口,提供通用的数据库操作方法 34 | * 35 | * @param <D> 实体类型(Domain/Entity) 36 | * @param <I> 主键类型(ID) 37 | */ 38 | @NoRepositoryBean 39 | public interface BaseRepository<D, I> extends JpaRepository<D, I>, JpaSpecificationExecutor<D> { 40 | 41 | /** 42 | * 根据ID集合批量查询实体列表 43 | * 44 | * @param ids 45 | * @param sort 46 | * @return 47 | */ 48 | List<D> findAllByIdIn(@NonNull Collection<I> ids, @NonNull Sort sort); 49 | } 50 | 51 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/controller/OidcController.java: -------------------------------------------------------------------------------- ```java 1 | package com.alibaba.apiopenplatform.controller; 2 | 3 | import com.alibaba.apiopenplatform.dto.result.AuthResult; 4 | import com.alibaba.apiopenplatform.dto.result.IdpResult; 5 | import com.alibaba.apiopenplatform.service.OidcService; 6 | import lombok.RequiredArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | import java.io.IOException; 13 | import java.util.List; 14 | 15 | @Slf4j 16 | @RestController 17 | @RequestMapping("/developers/oidc") 18 | @RequiredArgsConstructor 19 | public class OidcController { 20 | 21 | private final OidcService oidcService; 22 | 23 | @GetMapping("/authorize") 24 | public void authorize(@RequestParam String provider, 25 | @RequestParam(defaultValue = "/api/v1") String apiPrefix, 26 | HttpServletRequest request, 27 | HttpServletResponse response) throws IOException { 28 | String authUrl = oidcService.buildAuthorizationUrl(provider, apiPrefix, request); 29 | 30 | log.info("Redirecting to OIDC authorization URL: {}", authUrl); 31 | response.sendRedirect(authUrl); 32 | } 33 | 34 | @GetMapping("/callback") 35 | public AuthResult callback(@RequestParam String code, 36 | @RequestParam String state, 37 | HttpServletRequest request, 38 | HttpServletResponse response) { 39 | return oidcService.handleCallback(code, state, request, response); 40 | } 41 | 42 | @GetMapping("/providers") 43 | public List<IdpResult> getProviders() { 44 | return oidcService.getAvailableProviders(); 45 | } 46 | } 47 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/Administrator.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import javax.persistence.*; 23 | import java.util.Date; 24 | import lombok.Data; 25 | import lombok.NoArgsConstructor; 26 | import lombok.AllArgsConstructor; 27 | import lombok.Builder; 28 | 29 | /** 30 | * 管理员实体类,映射管理员账号信息 31 | * 32 | */ 33 | @Data 34 | @NoArgsConstructor 35 | @AllArgsConstructor 36 | @Builder 37 | @Entity 38 | @Table(name = "administrator", uniqueConstraints = { 39 | @UniqueConstraint(columnNames = {"adminId"}), 40 | @UniqueConstraint(columnNames = {"username"}) 41 | }) 42 | public class Administrator extends BaseEntity { 43 | @Id 44 | @GeneratedValue(strategy = GenerationType.IDENTITY) 45 | private Long id; 46 | 47 | @Column(nullable = false, unique = true, length = 64) 48 | private String adminId; 49 | 50 | @Column(nullable = false, unique = true, length = 64) 51 | private String username; 52 | 53 | @Column(nullable = false) 54 | private String passwordHash; 55 | 56 | } ``` -------------------------------------------------------------------------------- /portal-bootstrap/pom.xml: -------------------------------------------------------------------------------- ``` 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <project xmlns="http://maven.apache.org/POM/4.0.0" 3 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 | <modelVersion>4.0.0</modelVersion> 6 | <parent> 7 | <groupId>com.alibaba.himarket</groupId> 8 | <artifactId>himarket</artifactId> 9 | <version>1.0-SNAPSHOT</version> 10 | </parent> 11 | 12 | <artifactId>portal-bootstrap</artifactId> 13 | 14 | <properties> 15 | <maven.compiler.source>8</maven.compiler.source> 16 | <maven.compiler.target>8</maven.compiler.target> 17 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 18 | </properties> 19 | 20 | <dependencies> 21 | <dependency> 22 | <groupId>com.alibaba.himarket</groupId> 23 | <artifactId>portal-server</artifactId> 24 | <version>1.0-SNAPSHOT</version> 25 | </dependency> 26 | 27 | <!-- OkHttp for RestTemplate --> 28 | <dependency> 29 | <groupId>com.squareup.okhttp3</groupId> 30 | <artifactId>okhttp</artifactId> 31 | </dependency> 32 | 33 | </dependencies> 34 | 35 | <build> 36 | <plugins> 37 | <plugin> 38 | <groupId>org.springframework.boot</groupId> 39 | <artifactId>spring-boot-maven-plugin</artifactId> 40 | <version>2.7.18</version> 41 | <executions> 42 | <execution> 43 | <goals> 44 | <goal>repackage</goal> 45 | </goals> 46 | </execution> 47 | </executions> 48 | </plugin> 49 | </plugins> 50 | </build> 51 | 52 | </project> ``` -------------------------------------------------------------------------------- /portal-bootstrap/src/main/java/com/alibaba/apiopenplatform/config/AsyncConfig.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.config; 21 | 22 | import org.springframework.context.annotation.Bean; 23 | import org.springframework.context.annotation.Configuration; 24 | import org.springframework.scheduling.annotation.EnableAsync; 25 | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 26 | 27 | import java.util.concurrent.Executor; 28 | import java.util.concurrent.ThreadPoolExecutor; 29 | 30 | @Configuration 31 | @EnableAsync 32 | public class AsyncConfig { 33 | 34 | @Bean("taskExecutor") 35 | public Executor getTaskExecutor() { 36 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 37 | executor.setCorePoolSize(5); 38 | executor.setMaxPoolSize(10); 39 | executor.setQueueCapacity(25); 40 | executor.setThreadNamePrefix("TaskExecutor-"); 41 | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 42 | executor.initialize(); 43 | return executor; 44 | } 45 | } 46 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/DeveloperRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.Developer; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | import org.springframework.data.jpa.repository.JpaRepository; 26 | 27 | import java.util.Optional; 28 | import java.util.List; 29 | 30 | public interface DeveloperRepository extends BaseRepository<Developer, Long> { 31 | 32 | Optional<Developer> findByDeveloperId(String developerId); 33 | 34 | Optional<Developer> findByUsername(String username); 35 | 36 | List<Developer> findByPortalId(String portalId); 37 | 38 | Optional<Developer> findByPortalIdAndUsername(String portalId, String username); 39 | 40 | Optional<Developer> findByPortalIdAndEmail(String portalId, String email); 41 | 42 | Optional<Developer> findByDeveloperIdAndPortalId(String developerId, String portalId); 43 | 44 | Page<Developer> findByPortalId(String portalId, Pageable pageable); 45 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/MseNacosResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.aliyun.mse20190531.models.ListClustersResponseBody.ListClustersResponseBodyData; 23 | 24 | import lombok.Data; 25 | 26 | @Data 27 | public class MseNacosResult { 28 | private String instanceId; 29 | 30 | private String name; 31 | 32 | private String serverIntranetEndpoint; 33 | 34 | private String serverInternetEndpoint; 35 | 36 | private String version; 37 | 38 | public static MseNacosResult fromListClustersResponseBodyData(ListClustersResponseBodyData cluster) { 39 | MseNacosResult nacosResult = new MseNacosResult(); 40 | nacosResult.setName(cluster.getClusterAliasName()); 41 | nacosResult.setVersion(cluster.getVersionCode()); 42 | nacosResult.setInstanceId(cluster.getInstanceId()); 43 | nacosResult.setServerIntranetEndpoint(cluster.getIntranetDomain()); 44 | nacosResult.setServerInternetEndpoint(cluster.getInternetDomain()); 45 | return nacosResult; 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/ProductRefResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.entity.ProductRef; 24 | import com.alibaba.apiopenplatform.support.enums.SourceType; 25 | import com.alibaba.apiopenplatform.support.product.APIGRefConfig; 26 | import com.alibaba.apiopenplatform.support.product.HigressRefConfig; 27 | import com.alibaba.apiopenplatform.support.product.NacosRefConfig; 28 | import lombok.Data; 29 | 30 | @Data 31 | public class ProductRefResult implements OutputConverter<ProductRefResult, ProductRef> { 32 | 33 | private String productId; 34 | 35 | private SourceType sourceType; 36 | 37 | private String gatewayId; 38 | 39 | private APIGRefConfig apigRefConfig; 40 | 41 | // 新增:ADP AI 网关引用配置(与 APIGRefConfig 结构一致) 42 | private APIGRefConfig adpAIGatewayRefConfig; 43 | 44 | private HigressRefConfig higressRefConfig; 45 | 46 | private String nacosId; 47 | 48 | private NacosRefConfig nacosRefConfig; 49 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/ProductRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import org.springframework.stereotype.Repository; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | 26 | import java.util.Collection; 27 | import java.util.List; 28 | import java.util.Optional; 29 | 30 | import com.alibaba.apiopenplatform.entity.Product; 31 | 32 | @Repository 33 | public interface ProductRepository extends BaseRepository<Product, Long> { 34 | 35 | Optional<Product> findByProductId(String productId); 36 | 37 | Optional<Product> findByProductIdAndAdminId(String productId, String adminId); 38 | 39 | Optional<Product> findByNameAndAdminId(String name, String adminId); 40 | 41 | Page<Product> findByProductIdIn(Collection<String> productIds, Pageable pageable); 42 | 43 | List<Product> findByProductIdIn(Collection<String> productIds); 44 | 45 | Page<Product> findByAdminId(String adminId, Pageable pageable); 46 | 47 | Page<Product> findByCategory(String category, Pageable pageable); 48 | } 49 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/repository/ConsumerRepository.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.repository; 21 | 22 | import com.alibaba.apiopenplatform.entity.Consumer; 23 | import org.springframework.data.domain.Page; 24 | import org.springframework.data.domain.Pageable; 25 | 26 | import java.util.Collection; 27 | import java.util.List; 28 | import java.util.Optional; 29 | 30 | public interface ConsumerRepository extends BaseRepository<Consumer, Long> { 31 | 32 | Optional<Consumer> findByConsumerId(String consumerId); 33 | 34 | Optional<Consumer> findByDeveloperIdAndConsumerId(String developerId, String consumerId); 35 | 36 | Optional<Consumer> findByDeveloperIdAndName(String developerId, String name); 37 | 38 | Page<Consumer> findByDeveloperId(String developerId, Pageable pageable); 39 | 40 | Page<Consumer> findByPortalId(String portalId, Pageable pageable); 41 | 42 | List<Consumer> findAllByDeveloperId(String developerId); 43 | 44 | void deleteAllByDeveloperId(String developerId); 45 | 46 | List<Consumer> findByConsumerIdIn(Collection<String> consumerIds); 47 | } 48 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/product/UpdateProductParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.product; 21 | 22 | import cn.hutool.core.util.StrUtil; 23 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 24 | import com.alibaba.apiopenplatform.entity.Product; 25 | import com.alibaba.apiopenplatform.support.enums.ProductType; 26 | import com.alibaba.apiopenplatform.support.product.ProductIcon; 27 | import lombok.Data; 28 | 29 | import javax.validation.constraints.AssertTrue; 30 | 31 | @Data 32 | public class UpdateProductParam implements InputConverter<Product> { 33 | 34 | private String name; 35 | 36 | private String description; 37 | 38 | private ProductType type; 39 | 40 | private Boolean enableConsumerAuth; 41 | 42 | private String document; 43 | 44 | private ProductIcon icon; 45 | 46 | private String category; 47 | 48 | private Boolean autoApprove; 49 | 50 | @AssertTrue(message = "Icon大小不能超过16KB") 51 | public boolean checkIcon() { 52 | if (icon == null || StrUtil.isBlank(icon.getValue())) { 53 | return true; 54 | } 55 | return icon.getValue().length() < 16 * 1024; 56 | } 57 | } 58 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/src/types/api-product.ts: -------------------------------------------------------------------------------- ```typescript 1 | export interface ApiProductConfig { 2 | spec: string; 3 | meta: { 4 | source: string; 5 | type: string; 6 | } 7 | } 8 | 9 | // 产品图标类型 10 | export interface ProductIcon { 11 | type: 'URL' | 'BASE64'; 12 | value: string; 13 | } 14 | 15 | export interface ApiProductMcpConfig { 16 | mcpServerName: string; 17 | tools: string; 18 | meta: { 19 | source: string; 20 | mcpServerName: string; 21 | mcpServerConfig: any; 22 | fromType: string; 23 | protocol?: string; 24 | } 25 | mcpServerConfig: { 26 | path: string; 27 | domains: { 28 | domain: string; 29 | protocol: string; 30 | }[]; 31 | rawConfig?: unknown; 32 | } 33 | } 34 | 35 | // API 配置相关类型 36 | export interface RestAPIItem { 37 | apiId: string; 38 | apiName: string; 39 | } 40 | 41 | export interface HigressMCPItem { 42 | mcpServerName: string; 43 | fromGatewayType: 'HIGRESS'; 44 | } 45 | 46 | export interface NacosMCPItem { 47 | mcpServerName: string; 48 | fromGatewayType: 'NACOS'; 49 | namespaceId: string; 50 | } 51 | 52 | export interface APIGAIMCPItem { 53 | mcpServerName: string; 54 | fromGatewayType: 'APIG_AI' | 'ADP_AI_GATEWAY'; 55 | mcpRouteId: string; 56 | mcpServerId?: string; 57 | apiId?: string; 58 | type?: string; 59 | } 60 | 61 | export type ApiItem = RestAPIItem | HigressMCPItem | APIGAIMCPItem | NacosMCPItem; 62 | 63 | // 关联服务配置 64 | export interface LinkedService { 65 | productId: string; 66 | gatewayId?: string; 67 | nacosId?: string; 68 | sourceType: 'GATEWAY' | 'NACOS'; 69 | apigRefConfig?: RestAPIItem | APIGAIMCPItem; 70 | higressRefConfig?: HigressMCPItem; 71 | nacosRefConfig?: NacosMCPItem; 72 | adpAIGatewayRefConfig?: APIGAIMCPItem; 73 | } 74 | 75 | export interface ApiProduct { 76 | productId: string; 77 | name: string; 78 | description: string; 79 | type: 'REST_API' | 'MCP_SERVER'; 80 | category: string; 81 | status: 'PENDING' | 'READY' | 'PUBLISHED' | string; 82 | createAt: string; 83 | enableConsumerAuth?: boolean; 84 | autoApprove?: boolean; 85 | apiConfig?: ApiProductConfig; 86 | mcpConfig?: ApiProductMcpConfig; 87 | document?: string; 88 | icon?: ProductIcon | null; 89 | } 90 | ``` -------------------------------------------------------------------------------- /portal-bootstrap/src/main/java/com/alibaba/apiopenplatform/config/RestTemplateConfig.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.config; 21 | 22 | import lombok.RequiredArgsConstructor; 23 | import okhttp3.ConnectionPool; 24 | import okhttp3.OkHttpClient; 25 | import org.springframework.context.annotation.Bean; 26 | import org.springframework.context.annotation.Configuration; 27 | import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; 28 | import org.springframework.web.client.RestTemplate; 29 | 30 | import java.util.concurrent.TimeUnit; 31 | 32 | @Configuration 33 | public class RestTemplateConfig { 34 | 35 | @Bean 36 | public RestTemplate restTemplate(OkHttpClient okHttpClient) { 37 | // 使用OkHttp作为RestTemplate的底层客户端 38 | return new RestTemplate(new OkHttp3ClientHttpRequestFactory(okHttpClient)); 39 | } 40 | 41 | @Bean 42 | public OkHttpClient okHttpClient() { 43 | return new OkHttpClient.Builder() 44 | .connectTimeout(5, TimeUnit.SECONDS) 45 | .readTimeout(5, TimeUnit.SECONDS) 46 | .writeTimeout(5, TimeUnit.SECONDS) 47 | .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)) 48 | .build(); 49 | } 50 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/product/CreateProductRefParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.product; 21 | 22 | import cn.hutool.core.util.StrUtil; 23 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 24 | import com.alibaba.apiopenplatform.entity.ProductRef; 25 | import com.alibaba.apiopenplatform.support.enums.SourceType; 26 | import com.alibaba.apiopenplatform.support.product.APIGRefConfig; 27 | import com.alibaba.apiopenplatform.support.product.HigressRefConfig; 28 | import com.alibaba.apiopenplatform.support.product.NacosRefConfig; 29 | import lombok.Data; 30 | 31 | import javax.validation.constraints.AssertTrue; 32 | import javax.validation.constraints.NotNull; 33 | 34 | @Data 35 | public class CreateProductRefParam implements InputConverter<ProductRef> { 36 | 37 | @NotNull(message = "数据源类型不能为空") 38 | private SourceType sourceType; 39 | 40 | private String gatewayId; 41 | 42 | private String nacosId; 43 | 44 | private APIGRefConfig apigRefConfig; 45 | 46 | // 新增:ADP AI 网关引用配置(与 APIGRefConfig 结构一致) 47 | private APIGRefConfig adpAIGatewayRefConfig; 48 | 49 | private HigressRefConfig higressRefConfig; 50 | 51 | private NacosRefConfig nacosRefConfig; 52 | 53 | } ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/ProductResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.alibaba.apiopenplatform.dto.converter.OutputConverter; 23 | import com.alibaba.apiopenplatform.entity.Product; 24 | import com.alibaba.apiopenplatform.support.enums.ProductStatus; 25 | import com.alibaba.apiopenplatform.support.enums.ProductType; 26 | import com.alibaba.apiopenplatform.support.product.ProductIcon; 27 | import lombok.Data; 28 | 29 | import java.time.LocalDateTime; 30 | 31 | @Data 32 | public class ProductResult implements OutputConverter<ProductResult, Product> { 33 | 34 | private String productId; 35 | 36 | private String name; 37 | 38 | private String description; 39 | 40 | private ProductStatus status = ProductStatus.PENDING; 41 | 42 | private Boolean enableConsumerAuth = false; 43 | 44 | private ProductType type; 45 | 46 | private String document; 47 | 48 | private ProductIcon icon; 49 | 50 | private String category; 51 | 52 | private Boolean autoApprove; 53 | 54 | private LocalDateTime createAt; 55 | 56 | private LocalDateTime updatedAt; 57 | 58 | private APIConfigResult apiConfig; 59 | 60 | private MCPConfigResult mcpConfig; 61 | 62 | private Boolean enabled; 63 | } 64 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/src/components/console/NacosTypeSelector.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { Modal, Radio, Button, Space } from 'antd' 2 | import { useState } from 'react' 3 | 4 | export type NacosImportType = 'OPEN_SOURCE' | 'MSE' 5 | 6 | interface NacosTypeSelectorProps { 7 | visible: boolean 8 | onCancel: () => void 9 | onSelect: (type: NacosImportType) => void 10 | } 11 | 12 | export default function NacosTypeSelector({ visible, onCancel, onSelect }: NacosTypeSelectorProps) { 13 | const [selectedType, setSelectedType] = useState<NacosImportType>('MSE') 14 | 15 | const handleConfirm = () => { 16 | onSelect(selectedType) 17 | } 18 | 19 | const handleCancel = () => { 20 | setSelectedType('OPEN_SOURCE') 21 | onCancel() 22 | } 23 | 24 | return ( 25 | <Modal 26 | title="选择 Nacos 类型" 27 | open={visible} 28 | onCancel={handleCancel} 29 | footer={[ 30 | <Button key="cancel" onClick={handleCancel}> 31 | 取消 32 | </Button>, 33 | <Button key="confirm" type="primary" onClick={handleConfirm}> 34 | 确定 35 | </Button> 36 | ]} 37 | width={500} 38 | > 39 | <div className="py-4"> 40 | <Radio.Group 41 | value={selectedType} 42 | onChange={(e) => setSelectedType(e.target.value)} 43 | className="w-full" 44 | > 45 | <Space direction="vertical" className="w-full"> 46 | <Radio value="MSE" className="w-full p-3 border rounded-lg hover:bg-gray-50"> 47 | <div className="ml-2"> 48 | <div className="font-medium">MSE Nacos</div> 49 | <div className="text-sm text-gray-500">通过阿里云 MSE 账号授权后选择实例导入</div> 50 | </div> 51 | </Radio> 52 | <Radio value="OPEN_SOURCE" className="w-full p-3 border rounded-lg hover:bg-gray-50"> 53 | <div className="ml-2"> 54 | <div className="font-medium">开源 Nacos</div> 55 | <div className="text-sm text-gray-500">使用已有自建/开源 Nacos 地址登录创建</div> 56 | </div> 57 | </Radio> 58 | </Space> 59 | </Radio.Group> 60 | </div> 61 | </Modal> 62 | ) 63 | } 64 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/PortalDomain.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import com.alibaba.apiopenplatform.support.enums.DomainType; 23 | import com.alibaba.apiopenplatform.support.enums.ProtocolType; 24 | import lombok.Data; 25 | import lombok.EqualsAndHashCode; 26 | 27 | import javax.persistence.*; 28 | 29 | @Entity 30 | @Table(name = "portal_domain", 31 | uniqueConstraints = { 32 | @UniqueConstraint(columnNames = {"domain"}, name = "uk_domain") 33 | } 34 | ) 35 | @Data 36 | @EqualsAndHashCode(callSuper = true) 37 | public class PortalDomain extends BaseEntity { 38 | @Id 39 | @GeneratedValue(strategy = GenerationType.IDENTITY) 40 | private Long id; 41 | 42 | @Column(name = "portal_id", length = 64, nullable = false) 43 | private String portalId; 44 | 45 | @Column(name = "domain", length = 128, nullable = false) 46 | private String domain; 47 | 48 | @Enumerated(EnumType.STRING) 49 | @Column(name = "type", length = 32, nullable = false) 50 | private DomainType type = DomainType.DEFAULT; 51 | 52 | @Column(name = "protocol", length = 32, nullable = false) 53 | @Enumerated(EnumType.STRING) 54 | private ProtocolType protocol = ProtocolType.HTTP; 55 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/DeveloperExternalIdentity.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import javax.persistence.*; 23 | 24 | import com.alibaba.apiopenplatform.support.enums.DeveloperAuthType; 25 | import lombok.Data; 26 | import lombok.NoArgsConstructor; 27 | import lombok.AllArgsConstructor; 28 | import lombok.Builder; 29 | 30 | @Data 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | @Builder 34 | @Entity 35 | @Table(name = "developer_external_identity", uniqueConstraints = { 36 | @UniqueConstraint(columnNames = {"provider", "subject"}) 37 | }) 38 | public class DeveloperExternalIdentity { 39 | @Id 40 | @GeneratedValue(strategy = GenerationType.IDENTITY) 41 | private Long id; 42 | 43 | @ManyToOne 44 | @JoinColumn(name = "developer_id", referencedColumnName = "developerId", nullable = false) 45 | private Developer developer; 46 | 47 | @Column(nullable = false, length = 32) 48 | private String provider; 49 | 50 | @Column(nullable = false, length = 128) 51 | private String subject; 52 | 53 | @Column(length = 128) 54 | private String displayName; 55 | 56 | @Column(length = 32) 57 | private DeveloperAuthType authType; 58 | 59 | @Column(columnDefinition = "json") 60 | private String rawInfoJson; 61 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/ConsumerRef.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import com.alibaba.apiopenplatform.converter.GatewayConfigConverter; 23 | import com.alibaba.apiopenplatform.support.enums.GatewayType; 24 | import com.alibaba.apiopenplatform.support.gateway.GatewayConfig; 25 | import lombok.*; 26 | 27 | import javax.persistence.*; 28 | 29 | @Entity 30 | @Table(name = "consumer_ref") 31 | @Data 32 | @Builder 33 | @AllArgsConstructor 34 | @NoArgsConstructor 35 | @EqualsAndHashCode(callSuper = true) 36 | public class ConsumerRef extends BaseEntity { 37 | 38 | @Id 39 | @GeneratedValue(strategy = GenerationType.IDENTITY) 40 | private Long id; 41 | 42 | @Column(name = "consumer_id", length = 64, nullable = false) 43 | private String consumerId; 44 | 45 | @Column(name = "gateway_type", length = 32, nullable = false) 46 | @Enumerated(EnumType.STRING) 47 | private GatewayType gatewayType; 48 | 49 | @Column(name = "gw_consumer_id", length = 64, nullable = false) 50 | private String gwConsumerId; 51 | 52 | @Column(name = "gateway_config", columnDefinition = "json", nullable = false) 53 | @Convert(converter = GatewayConfigConverter.class) 54 | private GatewayConfig gatewayConfig; 55 | } 56 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/src/components/portal/PortalFormModal.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import { Modal, Form, Input, message } from 'antd' 2 | import { useEffect } from 'react' 3 | import { portalApi } from '@/lib/api' 4 | import { Portal } from '@/types' 5 | 6 | interface PortalFormModalProps { 7 | visible: boolean 8 | onCancel: () => void 9 | onSuccess: () => void 10 | portal: Portal | null 11 | } 12 | 13 | export default function PortalFormModal({ 14 | visible, 15 | onCancel, 16 | onSuccess, 17 | portal, 18 | }: PortalFormModalProps) { 19 | const [form] = Form.useForm() 20 | 21 | useEffect(() => { 22 | if (visible && portal) { 23 | form.setFieldsValue({ 24 | name: portal.name, 25 | description: portal.description || '', 26 | }) 27 | } 28 | }, [visible, portal, form]) 29 | 30 | const handleOk = async () => { 31 | try { 32 | const values = await form.validateFields() 33 | if (!portal) return 34 | 35 | await portalApi.updatePortal(portal.portalId, { 36 | name: values.name, 37 | description: values.description, 38 | portalSettingConfig: portal.portalSettingConfig, 39 | portalDomainConfig: portal.portalDomainConfig, 40 | portalUiConfig: portal.portalUiConfig, 41 | }) 42 | 43 | message.success('Portal信息更新成功') 44 | form.resetFields() 45 | onSuccess() 46 | } catch (error) { 47 | message.error('更新失败,请稍后重试') 48 | } 49 | } 50 | 51 | const handleCancel = () => { 52 | form.resetFields() 53 | onCancel() 54 | } 55 | 56 | return ( 57 | <Modal 58 | title="编辑Portal" 59 | open={visible} 60 | onOk={handleOk} 61 | onCancel={handleCancel} 62 | okText="保存" 63 | cancelText="取消" 64 | width={600} 65 | destroyOnClose 66 | > 67 | <Form form={form} layout="vertical"> 68 | <Form.Item 69 | name="name" 70 | label="Portal名称" 71 | rules={[{ required: true, message: "请输入Portal名称" }]} 72 | > 73 | <Input placeholder="请输入Portal名称" /> 74 | </Form.Item> 75 | 76 | <Form.Item 77 | name="description" 78 | label="描述" 79 | > 80 | <Input.TextArea rows={3} placeholder="请输入Portal描述" /> 81 | </Form.Item> 82 | </Form> 83 | </Modal> 84 | ) 85 | } 86 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/core/constant/Resources.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.core.constant; 21 | 22 | public class Resources { 23 | 24 | public static final String ADMINISTRATOR = "Administrator"; 25 | 26 | public static final String PORTAL = "Portal"; 27 | 28 | public static final String PORTAL_SETTING = "PortalSetting"; 29 | 30 | public static final String PORTAL_UI = "PortalUI"; 31 | 32 | public static final String PORTAL_DOMAIN = "PortalDomain"; 33 | 34 | public static final String OAUTH2_CONFIG = "OAuth2Config"; 35 | 36 | public static final String PUBLIC_KEY = "PublicKey"; 37 | 38 | public static final String OIDC_CONFIG = "OidcConfig"; 39 | 40 | public static final String PRODUCT = "Product"; 41 | 42 | public static final String PRODUCT_SETTING = "ProductSetting"; 43 | 44 | public static final String DEVELOPER = "Developer"; 45 | 46 | public static final String CONSUMER = "Consumer"; 47 | 48 | public static final String CONSUMER_CREDENTIAL = "ConsumerCredential"; 49 | 50 | public static final String GATEWAY = "Gateway"; 51 | 52 | public static final String PRODUCT_REF = "ProductRef"; 53 | 54 | public static final String NACOS_INSTANCE = "NacosInstance"; 55 | 56 | public static final String SUBSCRIPTION = "Subscription"; 57 | 58 | } 59 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/bin/replace_var.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | from jinja2 import Template 4 | import sys 5 | import os 6 | import traceback 7 | import json 8 | 9 | 10 | def readFileTrimspace(filepath): 11 | try: 12 | result = list() 13 | is_yaml = 'yaml' in filepath or 'yml' in filepath 14 | if os.path.isfile(filepath): 15 | f = open(filepath, 'r') 16 | for line in f.readlines(): 17 | line = (line.strip('\n') if is_yaml else line.strip()) 18 | if not len(line): 19 | continue 20 | result.append(line) 21 | return "\n".join(result) 22 | except: 23 | traceback.print_exc() 24 | return "" 25 | 26 | def readFile(filepath): 27 | try: 28 | if not os.path.isfile(filepath): 29 | print("The input [%s] is not a file" % filepath) 30 | return "" 31 | if os.path.isfile(filepath): 32 | try: 33 | f = open(filepath, 'r') 34 | return f.read() 35 | finally: 36 | if f: 37 | f.close() 38 | except: 39 | traceback.print_exc() 40 | return "" 41 | 42 | 43 | def writeFile(filepath, content): 44 | try: 45 | open(filepath, 'w+').write(content) 46 | except: 47 | traceback.print_exc() 48 | 49 | 50 | def dockerenv2json(): 51 | envJson = {} 52 | with open('/.dockerenv') as ifs: 53 | data = ifs.read() 54 | assert len(data) > 2, 'invalid dockerenv' 55 | envlist = json.loads(data) 56 | for env in envlist: 57 | indexOfEqual = env.index('=') 58 | if indexOfEqual > 0: 59 | key = env[0: indexOfEqual] 60 | value = env[indexOfEqual + 1:] 61 | envJson[key] = value 62 | return envJson 63 | 64 | 65 | def createVarMap(filepath): 66 | map = os.environ 67 | # add more param to map 68 | return map 69 | 70 | 71 | def main(): 72 | filepath = sys.argv[1] if len(sys.argv) > 1 else '' 73 | t = Template(readFile(filepath)) 74 | map = createVarMap(filepath) 75 | ret = t.render(map) 76 | writeFile(filepath, ret) 77 | 78 | 79 | if __name__ == "__main__": 80 | reload(sys) 81 | sys.setdefaultencoding('utf-8') 82 | main() ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/bin/replace_var.py: -------------------------------------------------------------------------------- ```python 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | from jinja2 import Template 4 | import sys 5 | import os 6 | import traceback 7 | import json 8 | 9 | 10 | def readFileTrimspace(filepath): 11 | try: 12 | result = list() 13 | is_yaml = 'yaml' in filepath or 'yml' in filepath 14 | if os.path.isfile(filepath): 15 | f = open(filepath, 'r') 16 | for line in f.readlines(): 17 | line = (line.strip('\n') if is_yaml else line.strip()) 18 | if not len(line): 19 | continue 20 | result.append(line) 21 | return "\n".join(result) 22 | except: 23 | traceback.print_exc() 24 | return "" 25 | 26 | def readFile(filepath): 27 | try: 28 | if not os.path.isfile(filepath): 29 | print("The input [%s] is not a file" % filepath) 30 | return "" 31 | if os.path.isfile(filepath): 32 | try: 33 | f = open(filepath, 'r') 34 | return f.read() 35 | finally: 36 | if f: 37 | f.close() 38 | except: 39 | traceback.print_exc() 40 | return "" 41 | 42 | 43 | def writeFile(filepath, content): 44 | try: 45 | open(filepath, 'w+').write(content) 46 | except: 47 | traceback.print_exc() 48 | 49 | 50 | def dockerenv2json(): 51 | envJson = {} 52 | with open('/.dockerenv') as ifs: 53 | data = ifs.read() 54 | assert len(data) > 2, 'invalid dockerenv' 55 | envlist = json.loads(data) 56 | for env in envlist: 57 | indexOfEqual = env.index('=') 58 | if indexOfEqual > 0: 59 | key = env[0: indexOfEqual] 60 | value = env[indexOfEqual + 1:] 61 | envJson[key] = value 62 | return envJson 63 | 64 | 65 | def createVarMap(filepath): 66 | map = os.environ 67 | # add more param to map 68 | return map 69 | 70 | 71 | def main(): 72 | filepath = sys.argv[1] if len(sys.argv) > 1 else '' 73 | t = Template(readFile(filepath)) 74 | map = createVarMap(filepath) 75 | ret = t.render(map) 76 | writeFile(filepath, ret) 77 | 78 | 79 | if __name__ == "__main__": 80 | reload(sys) 81 | sys.setdefaultencoding('utf-8') 82 | main() ``` -------------------------------------------------------------------------------- /portal-bootstrap/src/main/java/com/alibaba/apiopenplatform/config/FilterConfig.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.config; 21 | 22 | import com.alibaba.apiopenplatform.core.security.ContextHolder; 23 | import com.alibaba.apiopenplatform.filter.PortalResolvingFilter; 24 | import com.alibaba.apiopenplatform.service.PortalService; 25 | import lombok.RequiredArgsConstructor; 26 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.core.Ordered; 30 | 31 | @Configuration 32 | @RequiredArgsConstructor 33 | public class FilterConfig { 34 | 35 | private final PortalService portalService; 36 | 37 | private final ContextHolder contextHolder; 38 | 39 | @Bean 40 | public FilterRegistrationBean<PortalResolvingFilter> portalResolvingFilter() { 41 | FilterRegistrationBean<PortalResolvingFilter> registrationBean = new FilterRegistrationBean<>(); 42 | 43 | PortalResolvingFilter filter = new PortalResolvingFilter(portalService, contextHolder); 44 | registrationBean.setFilter(filter); 45 | registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); 46 | registrationBean.addUrlPatterns("/*"); 47 | 48 | return registrationBean; 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/result/AdpMCPServerResult.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.result; 21 | 22 | import com.fasterxml.jackson.annotation.JsonProperty; 23 | import lombok.Data; 24 | import lombok.EqualsAndHashCode; 25 | 26 | import java.util.List; 27 | 28 | @EqualsAndHashCode(callSuper = true) 29 | @Data 30 | public class AdpMCPServerResult extends GatewayMCPServerResult { 31 | 32 | private String gwInstanceId; 33 | 34 | @JsonProperty("name") 35 | private String name; 36 | 37 | private String description; 38 | private List<String> domains; 39 | private List<Service> services; 40 | private ConsumerAuthInfo consumerAuthInfo; 41 | private String rawConfigurations; 42 | private String type; 43 | private String dsn; 44 | private String dbType; 45 | private String upstreamPathPrefix; 46 | 47 | /** 48 | * 确保 mcpServerName 字段被正确设置 49 | */ 50 | public void setName(String name) { 51 | this.name = name; 52 | // 同时设置父类的 mcpServerName 字段 53 | this.setMcpServerName(name); 54 | } 55 | 56 | @Data 57 | public static class Service { 58 | private String name; 59 | private Integer port; 60 | private String version; 61 | private Integer weight; 62 | } 63 | 64 | @Data 65 | public static class ConsumerAuthInfo { 66 | private String type; 67 | private Boolean enable; 68 | private List<String> allowedConsumers; 69 | } 70 | } 71 | 72 | 73 | ``` -------------------------------------------------------------------------------- /portal-server/src/main/java/com/alibaba/apiopenplatform/dto/params/product/CreateProductParam.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.dto.params.product; 21 | 22 | import cn.hutool.core.util.StrUtil; 23 | import com.alibaba.apiopenplatform.dto.converter.InputConverter; 24 | import com.alibaba.apiopenplatform.entity.Product; 25 | import com.alibaba.apiopenplatform.support.enums.ProductType; 26 | import com.alibaba.apiopenplatform.support.product.ProductIcon; 27 | import lombok.Data; 28 | 29 | import javax.validation.constraints.AssertTrue; 30 | import javax.validation.constraints.NotBlank; 31 | import javax.validation.constraints.NotNull; 32 | import javax.validation.constraints.Size; 33 | 34 | @Data 35 | public class CreateProductParam implements InputConverter<Product> { 36 | 37 | @NotBlank(message = "API产品名称不能为空") 38 | @Size(max = 50, message = "API产品名称长度不能超过50个字符") 39 | private String name; 40 | 41 | @Size(max = 256, message = "API产品描述长度不能超过256个字符") 42 | private String description; 43 | 44 | @NotNull(message = "API产品类型不能为空") 45 | private ProductType type; 46 | 47 | private String document; 48 | 49 | private ProductIcon icon; 50 | 51 | private String category; 52 | 53 | private Boolean autoApprove; 54 | 55 | @AssertTrue(message = "Icon大小不能超过16KB") 56 | public boolean checkIcon() { 57 | if (icon == null || StrUtil.isBlank(icon.getValue())) { 58 | return true; 59 | } 60 | return icon.getValue().length() < 16 * 1024; 61 | } 62 | } 63 | ``` -------------------------------------------------------------------------------- /deploy/helm/templates/himarket-server-deployment.yaml: -------------------------------------------------------------------------------- ```yaml 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: himarket-server 5 | labels: 6 | app: himarket-server 7 | spec: 8 | replicas: {{ .Values.server.replicaCount }} 9 | selector: 10 | matchLabels: 11 | app: himarket-server 12 | template: 13 | metadata: 14 | labels: 15 | app: himarket-server 16 | spec: 17 | {{- with .Values.imagePullSecrets }} 18 | imagePullSecrets: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | serviceAccountName: {{ include "himarket.serviceAccountName" . }} 22 | containers: 23 | - name: server 24 | image: "{{ .Values.hub }}/{{ .Values.server.image.repository }}:{{ .Values.server.image.tag}}" 25 | imagePullPolicy: {{ .Values.server.image.pullPolicy }} 26 | ports: 27 | - name: http 28 | containerPort: {{ .Values.server.serverPort }} 29 | protocol: TCP 30 | envFrom: 31 | - configMapRef: 32 | name: himarket-server # 非敏感配置 33 | {{- if .Values.mysql.enabled }} 34 | - secretRef: 35 | name: himarket-server-secret # 内置MySQL的敏感配置 36 | {{- end }} 37 | {{/* {{- with .Values.livenessProbe }}*/}} 38 | {{/* livenessProbe:*/}} 39 | {{/* {{- toYaml . | nindent 12 }}*/}} 40 | {{/* {{- end }}*/}} 41 | {{/* {{- with .Values.readinessProbe }}*/}} 42 | {{/* readinessProbe:*/}} 43 | {{/* {{- toYaml . | nindent 12 }}*/}} 44 | {{/* {{- end }}*/}} 45 | {{- with .Values.resources }} 46 | resources: 47 | {{- toYaml . | nindent 12 }} 48 | {{- end }} 49 | {{- with .Values.volumeMounts }} 50 | volumeMounts: 51 | {{- toYaml . | nindent 12 }} 52 | {{- end }} 53 | {{- with .Values.volumes }} 54 | volumes: 55 | {{- toYaml . | nindent 8 }} 56 | {{- end }} 57 | {{- with .Values.nodeSelector }} 58 | nodeSelector: 59 | {{- toYaml . | nindent 8 }} 60 | {{- end }} 61 | {{- with .Values.affinity }} 62 | affinity: 63 | {{- toYaml . | nindent 8 }} 64 | {{- end }} 65 | {{- with .Values.tolerations }} 66 | tolerations: 67 | {{- toYaml . | nindent 8 }} 68 | {{- end }} 69 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/NacosInstance.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import lombok.Data; 23 | import lombok.EqualsAndHashCode; 24 | 25 | import javax.persistence.*; 26 | 27 | /** 28 | * Nacos实例实体 29 | */ 30 | @EqualsAndHashCode(callSuper = true) 31 | @Entity 32 | @Table(name = "nacos_instance", 33 | uniqueConstraints = { 34 | @UniqueConstraint(columnNames = {"nacos_id"}, name = "uk_nacos_id"), 35 | }) 36 | @Data 37 | public class NacosInstance extends BaseEntity { 38 | 39 | @Id 40 | @GeneratedValue(strategy = GenerationType.IDENTITY) 41 | private Long id; 42 | 43 | @Column(name = "nacos_name", length = 64, nullable = false) 44 | private String nacosName; 45 | 46 | @Column(name = "nacos_id", length = 64, nullable = false) 47 | private String nacosId; 48 | 49 | @Column(name = "admin_id", length = 64, nullable = false) 50 | private String adminId; 51 | 52 | @Column(name = "server_url", length = 256, nullable = false) 53 | private String serverUrl; 54 | 55 | 56 | @Column(name = "username", length = 64) 57 | private String username; 58 | 59 | @Column(name = "password", length = 128) 60 | private String password; 61 | 62 | @Column(name = "access_key", length = 128) 63 | private String accessKey; 64 | 65 | @Column(name = "secret_key", length = 256) 66 | private String secretKey; 67 | 68 | @Column(name = "description", length = 512) 69 | private String description; 70 | } ``` -------------------------------------------------------------------------------- /portal-bootstrap/src/main/java/com/alibaba/apiopenplatform/config/PageConfig.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.config; 21 | 22 | import org.springframework.context.annotation.Bean; 23 | import org.springframework.context.annotation.Configuration; 24 | import org.springframework.data.domain.PageRequest; 25 | import org.springframework.data.domain.Sort; 26 | import org.springframework.data.web.PageableHandlerMethodArgumentResolver; 27 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 28 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 29 | 30 | import java.util.List; 31 | 32 | @Configuration 33 | public class PageConfig { 34 | @Bean 35 | public PageableHandlerMethodArgumentResolver pageableResolver() { 36 | PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver(); 37 | // 默认分页和排序 38 | resolver.setFallbackPageable(PageRequest.of(0, 100, 39 | Sort.by(Sort.Direction.DESC, "createAt"))); 40 | // 页码从1开始 41 | resolver.setOneIndexedParameters(true); 42 | return resolver; 43 | } 44 | 45 | @Bean 46 | public WebMvcConfigurer webMvcConfigurer() { 47 | return new WebMvcConfigurer() { 48 | @Override 49 | public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { 50 | resolvers.add(pageableResolver()); 51 | } 52 | }; 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/Developer.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import javax.persistence.*; 23 | import java.util.Date; 24 | 25 | import com.alibaba.apiopenplatform.support.enums.DeveloperAuthType; 26 | import com.alibaba.apiopenplatform.support.enums.DeveloperStatus; 27 | import lombok.Data; 28 | import lombok.NoArgsConstructor; 29 | import lombok.AllArgsConstructor; 30 | import lombok.Builder; 31 | 32 | @Data 33 | @NoArgsConstructor 34 | @AllArgsConstructor 35 | @Builder 36 | @Entity 37 | @Table(name = "developer", uniqueConstraints = { 38 | @UniqueConstraint(columnNames = {"developerId"}), 39 | @UniqueConstraint(columnNames = {"portalId", "username"}) 40 | }) 41 | public class Developer extends BaseEntity { 42 | 43 | @Id 44 | @GeneratedValue(strategy = GenerationType.IDENTITY) 45 | private Long id; 46 | 47 | @Column(nullable = false, unique = true, length = 64) 48 | private String developerId; 49 | 50 | @Column(length = 64) 51 | private String username; 52 | 53 | @Column() 54 | private String passwordHash; 55 | 56 | @Column(length = 128) 57 | private String email; 58 | 59 | @Column(nullable = false, length = 64) 60 | private String portalId; 61 | 62 | @Column(length = 256) 63 | private String avatarUrl; 64 | 65 | @Column(nullable = false, length = 16) 66 | @Enumerated(EnumType.STRING) 67 | private DeveloperStatus status; 68 | 69 | @Column(length = 16) 70 | @Enumerated(EnumType.STRING) 71 | private DeveloperAuthType authType; 72 | 73 | } ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/Consumer.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import com.alibaba.apiopenplatform.support.enums.ConsumerStatus; 23 | import lombok.Data; 24 | import lombok.EqualsAndHashCode; 25 | import org.hibernate.annotations.ColumnDefault; 26 | 27 | import javax.persistence.*; 28 | 29 | @Entity 30 | @Table(name = "consumer", 31 | uniqueConstraints = { 32 | @UniqueConstraint(columnNames = {"consumer_id"}, name = "uk_consumer_id"), 33 | @UniqueConstraint(columnNames = {"name", "portal_id", "developer_id"}, 34 | name = "uk_name_portal_developer") 35 | }) 36 | @Data 37 | @EqualsAndHashCode(callSuper = true) 38 | public class Consumer extends BaseEntity { 39 | 40 | @Id 41 | @GeneratedValue(strategy = GenerationType.IDENTITY) 42 | private Long id; 43 | 44 | @Column(name = "consumer_id", length = 64, nullable = false) 45 | private String consumerId; 46 | 47 | @Column(name = "name", length = 64, nullable = false) 48 | private String name; 49 | 50 | @Column(name = "description", length = 256) 51 | private String description; 52 | 53 | // @Enumerated(EnumType.STRING) 54 | // @Column(name = "status", length = 32, nullable = false) 55 | // private ConsumerStatus status; 56 | 57 | @Column(name = "portal_id", length = 64, nullable = false) 58 | private String portalId; 59 | 60 | @Column(name = "developer_id", length = 64, nullable = false) 61 | private String developerId; 62 | } 63 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/entity/ConsumerCredential.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.entity; 21 | 22 | import com.alibaba.apiopenplatform.converter.ApiKeyConfigConverter; 23 | import com.alibaba.apiopenplatform.converter.HmacConfigConverter; 24 | import com.alibaba.apiopenplatform.converter.JwtConfigConverter; 25 | import com.alibaba.apiopenplatform.support.consumer.ApiKeyConfig; 26 | import com.alibaba.apiopenplatform.support.consumer.HmacConfig; 27 | import com.alibaba.apiopenplatform.support.consumer.JwtConfig; 28 | import lombok.Data; 29 | 30 | import javax.persistence.*; 31 | 32 | @Entity 33 | @Table(name = "consumer_credential", 34 | uniqueConstraints = { 35 | @UniqueConstraint(columnNames = {"consumer_id"}, name = "uk_consumer_id") 36 | }) 37 | @Data 38 | public class ConsumerCredential extends BaseEntity { 39 | 40 | @Id 41 | @GeneratedValue(strategy = GenerationType.IDENTITY) 42 | private Long id; 43 | 44 | @Column(name = "consumer_id", nullable = false) 45 | private String consumerId; 46 | 47 | @Column(name = "apikey_config", columnDefinition = "json") 48 | @Convert(converter = ApiKeyConfigConverter.class) 49 | private ApiKeyConfig apiKeyConfig; 50 | 51 | @Column(name = "hmac_config", columnDefinition = "json") 52 | @Convert(converter = HmacConfigConverter.class) 53 | private HmacConfig hmacConfig; 54 | 55 | @Column(name = "jwt_config", columnDefinition = "json") 56 | @Convert(converter = JwtConfigConverter.class) 57 | private JwtConfig jwtConfig; 58 | } 59 | ``` -------------------------------------------------------------------------------- /portal-dal/src/main/java/com/alibaba/apiopenplatform/support/common/Encryptor.java: -------------------------------------------------------------------------------- ```java 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.alibaba.apiopenplatform.support.common; 21 | 22 | import cn.hutool.core.util.CharsetUtil; 23 | import cn.hutool.core.util.StrUtil; 24 | import cn.hutool.crypto.SecureUtil; 25 | import cn.hutool.crypto.symmetric.AES; 26 | import cn.hutool.extra.spring.SpringUtil; 27 | import lombok.extern.slf4j.Slf4j; 28 | 29 | @Slf4j 30 | public class Encryptor { 31 | 32 | private static String ROOT_KEY; 33 | 34 | private static AES getAes() { 35 | if (StrUtil.isBlank(ROOT_KEY)) { 36 | ROOT_KEY = SpringUtil.getProperty("encryption.root-key"); 37 | } 38 | 39 | if (StrUtil.isBlank(ROOT_KEY)) { 40 | throw new RuntimeException("Encryption root key is not set"); 41 | } 42 | 43 | return SecureUtil.aes(ROOT_KEY.getBytes(CharsetUtil.CHARSET_UTF_8)); 44 | } 45 | 46 | public static String encrypt(String value) { 47 | if (StrUtil.isBlank(value)) { 48 | return value; 49 | } 50 | try { 51 | return getAes().encryptHex(value); 52 | } catch (Exception e) { 53 | log.error("Encrypt failed: {}", e.getMessage()); 54 | return value; 55 | } 56 | } 57 | 58 | public static String decrypt(String value) { 59 | if (StrUtil.isBlank(value)) { 60 | return value; 61 | } 62 | try { 63 | return getAes().decryptStr(value); 64 | } catch (Exception e) { 65 | log.error("Decrypt failed: {}", e.getMessage()); 66 | return value; 67 | } 68 | } 69 | } 70 | ``` -------------------------------------------------------------------------------- /portal-web/api-portal-admin/nginx.conf: -------------------------------------------------------------------------------- ``` 1 | user nginx; 2 | worker_processes auto; 3 | error_log /var/log/nginx/error.log; 4 | pid /run/nginx.pid; 5 | 6 | # Load dynamic modules. See /usr/share/nginx/README.dynamic. 7 | include /usr/share/nginx/modules/*.conf; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | tcp_nopush on; 22 | tcp_nodelay off; 23 | gzip on; 24 | gzip_http_version 1.0; 25 | gzip_comp_level 2; 26 | gzip_proxied any; 27 | gzip_types text/plain text/css application/javascript text/xml application/xml+rss; 28 | keepalive_timeout 65; 29 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 30 | ssl_ciphers HIGH:!aNULL:!MD5; 31 | client_max_body_size 80M; 32 | server_tokens off; 33 | 34 | include /etc/nginx/mime.types; 35 | default_type application/octet-stream; 36 | 37 | # Load modular configuration files from the /etc/nginx/conf.d directory. 38 | # See http://nginx.org/en/docs/ngx_core_module.html#include 39 | # for more information. 40 | include /etc/nginx/conf.d/*.conf; 41 | 42 | # HTTP Server 43 | server { 44 | # Port to listen on, can also be set in IP:PORT format 45 | listen 8000; 46 | 47 | # compression-webpack-plugin 配置 48 | gzip on; 49 | gzip_min_length 1k; 50 | gzip_comp_level 9; 51 | gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; 52 | gzip_vary on; 53 | # 配置禁用 gzip 条件,支持正则,此处表示 ie6 及以下不启用 gzip(因为ie低版本不支持) 54 | gzip_disable "MSIE [1-6]\."; 55 | 56 | add_header Access-Control-Allow-Origin *; 57 | add_header Access-Control-Allow-Headers Content-Type; 58 | add_header Access-Control-Allow-Methods GET,POST,OPTIONS; 59 | 60 | include "/etc/nginx/default.d/*.conf"; 61 | 62 | location /status { 63 | stub_status on; 64 | access_log off; 65 | allow 127.0.0.1; 66 | deny all; 67 | } 68 | } 69 | } ``` -------------------------------------------------------------------------------- /portal-web/api-portal-frontend/nginx.conf: -------------------------------------------------------------------------------- ``` 1 | user nginx; 2 | worker_processes auto; 3 | error_log /var/log/nginx/error.log; 4 | pid /run/nginx.pid; 5 | 6 | # Load dynamic modules. See /usr/share/nginx/README.dynamic. 7 | include /usr/share/nginx/modules/*.conf; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 15 | '$status $body_bytes_sent "$http_referer" ' 16 | '"$http_user_agent" "$http_x_forwarded_for"'; 17 | 18 | access_log /var/log/nginx/access.log main; 19 | 20 | sendfile on; 21 | tcp_nopush on; 22 | tcp_nodelay off; 23 | gzip on; 24 | gzip_http_version 1.0; 25 | gzip_comp_level 2; 26 | gzip_proxied any; 27 | gzip_types text/plain text/css application/javascript text/xml application/xml+rss; 28 | keepalive_timeout 65; 29 | ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 30 | ssl_ciphers HIGH:!aNULL:!MD5; 31 | client_max_body_size 80M; 32 | server_tokens off; 33 | 34 | include /etc/nginx/mime.types; 35 | default_type application/octet-stream; 36 | 37 | # Load modular configuration files from the /etc/nginx/conf.d directory. 38 | # See http://nginx.org/en/docs/ngx_core_module.html#include 39 | # for more information. 40 | include /etc/nginx/conf.d/*.conf; 41 | 42 | # HTTP Server 43 | server { 44 | # Port to listen on, can also be set in IP:PORT format 45 | listen 8000; 46 | 47 | # compression-webpack-plugin 配置 48 | gzip on; 49 | gzip_min_length 1k; 50 | gzip_comp_level 9; 51 | gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; 52 | gzip_vary on; 53 | # 配置禁用 gzip 条件,支持正则,此处表示 ie6 及以下不启用 gzip(因为ie低版本不支持) 54 | gzip_disable "MSIE [1-6]\."; 55 | 56 | add_header Access-Control-Allow-Origin *; 57 | add_header Access-Control-Allow-Headers Content-Type; 58 | add_header Access-Control-Allow-Methods GET,POST,OPTIONS; 59 | 60 | include "/etc/nginx/default.d/*.conf"; 61 | 62 | location /status { 63 | stub_status on; 64 | access_log off; 65 | allow 127.0.0.1; 66 | deny all; 67 | } 68 | } 69 | } ```