diff --git a/sk-module-data/sk-module-data-api/pom.xml b/sk-module-data/sk-module-data-api/pom.xml index 034c960e6..27c01706f 100644 --- a/sk-module-data/sk-module-data-api/pom.xml +++ b/sk-module-data/sk-module-data-api/pom.xml @@ -4,7 +4,7 @@ cn.iocoder.cloud sk-module-data - 2.4.1-jdk8-SNAPSHOT + ${revision} 4.0.0 sk-module-data-api diff --git a/sk-module-data/sk-module-data-biz/pom.xml b/sk-module-data/sk-module-data-biz/pom.xml index f6febd2bc..ace35e21d 100644 --- a/sk-module-data/sk-module-data-biz/pom.xml +++ b/sk-module-data/sk-module-data-biz/pom.xml @@ -181,7 +181,7 @@ true lib/ false - cn.iocoder.yudao.module.system.SystemServerApplication + org.sk.module.data.SkModuleDataBizApplication ./resources/ @@ -217,7 +217,7 @@ - + diff --git a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/config/SecurityConfiguration.java b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/config/SecurityConfiguration.java index 9148980ce..5d5130fbe 100644 --- a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/config/SecurityConfiguration.java +++ b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/config/SecurityConfiguration.java @@ -32,6 +32,7 @@ public class SecurityConfiguration { .requestMatchers("/actuator/**").permitAll(); // RPC 服务的安全配置 registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll(); + registry.requestMatchers( "/finance/**").permitAll(); } }; diff --git a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/controller/finance/FinanceController.java b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/controller/finance/FinanceController.java index 07cbef63a..9e4b25a85 100644 --- a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/controller/finance/FinanceController.java +++ b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/controller/finance/FinanceController.java @@ -4,21 +4,21 @@ package org.sk.module.data.controller.finance; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import org.sk.module.data.dal.bo.finance.FinanceBO; import org.sk.module.data.dal.param.finance.FinanceParam; import org.sk.module.data.dal.param.finance.IncomeAndTaxParam; import org.sk.module.data.dal.vo.FinanceVO; import org.sk.module.data.service.finance.FinanceService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; import javax.annotation.security.PermitAll; import javax.validation.Valid; import java.util.List; - +@Tag(name = "对外接口 - 财务数据") @RestController @RequestMapping("/finance") public class FinanceController { @@ -33,6 +33,7 @@ public class FinanceController { return "hello wzc"; } + @Operation(summary = "获取财务信息") @GetMapping("/getFinanceInfo") public CommonResult getFinanceInfo(@Valid @RequestBody FinanceParam financeParam) { @@ -47,8 +48,8 @@ public class FinanceController { * @param param * @return */ - @PermitAll - @GetMapping("/getIncomeAndTax") + @Operation(summary = "根据拼接的统一社会信用编码以及年份获取数据") + @PostMapping("/getIncomeAndTax") public CommonResult> getIncomeAndTax(@Valid @RequestBody IncomeAndTaxParam param) { return CommonResult.success(financeService.getIncomeAndTax(param)); } diff --git a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/dal/mapper/auth/AuthClientMapper.java b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/dal/mapper/auth/AuthClientMapper.java new file mode 100644 index 000000000..a8acb095f --- /dev/null +++ b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/dal/mapper/auth/AuthClientMapper.java @@ -0,0 +1,19 @@ +package org.sk.module.data.dal.mapper.auth; + +import com.baomidou.dynamic.datasource.annotation.DS; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.sk.module.data.dal.bo.finance.FinanceBO; + +import java.util.List; + +/** + * @author haoran + */ +@Mapper +@DS("master") +public interface AuthClientMapper { + + int selectClientByIdAndSecret(@Param("id")String id, @Param("secret")String secret); + +} diff --git a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/filter/AuthFilter.java b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/filter/AuthFilter.java new file mode 100644 index 000000000..f56e9f220 --- /dev/null +++ b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/filter/AuthFilter.java @@ -0,0 +1,59 @@ +package org.sk.module.data.filter; + +import org.sk.module.data.dal.mapper.auth.AuthClientMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; + +@Component +public class AuthFilter implements Filter { + + @Autowired + @Qualifier("requestMappingHandlerMapping") // 或 "controllerEndpointHandlerMapping" + private RequestMappingHandlerMapping handlerMapping; + + @Autowired + private AuthClientMapper authClientMapper; + + public AuthFilter( RequestMappingHandlerMapping requestMappingHandlerMapping) { + this.handlerMapping = requestMappingHandlerMapping; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpServletResponse httpResponse = (HttpServletResponse) response; + + // 获取请求头中的密钥和 ID + String id = httpRequest.getHeader("X-Id"); + String secretKey = httpRequest.getHeader("X-Secret-Key"); + + // 校验 ID 和密钥是否匹配 + if (isValid(id, secretKey)) { + chain.doFilter(request, response); + } else { + httpResponse.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403 Forbidden + httpResponse.setContentType("application/json"); + httpResponse.getWriter().write("{\"error\": \"Invalid ID or Secret Key\"}"); + } + } + + + /** + * 校验 ID 和密钥是否匹配 + */ + private boolean isValid(String id, String secretKey) { + // 示例逻辑:从数据库中查询 ID 和密钥是否匹配 + return authClientMapper.selectClientByIdAndSecret(id,secretKey) == 1; + } +} diff --git a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/service/finance/FinanceServiceImpl.java b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/service/finance/FinanceServiceImpl.java index 08ffff3e4..d5da80f8c 100644 --- a/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/service/finance/FinanceServiceImpl.java +++ b/sk-module-data/sk-module-data-biz/src/main/java/org/sk/module/data/service/finance/FinanceServiceImpl.java @@ -16,7 +16,7 @@ import java.util.Arrays; import java.util.List; @Service -@DS("master") +@DS("slave1") public class FinanceServiceImpl implements FinanceService { diff --git a/sk-module-data/sk-module-data-biz/src/main/resources/mappers/auth/AuthClientMapper.xml b/sk-module-data/sk-module-data-biz/src/main/resources/mappers/auth/AuthClientMapper.xml new file mode 100644 index 000000000..8fe3186e3 --- /dev/null +++ b/sk-module-data/sk-module-data-biz/src/main/resources/mappers/auth/AuthClientMapper.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/yudao-gateway/src/main/resources/application.yaml b/yudao-gateway/src/main/resources/application.yaml index dd298820b..d9860cc3b 100644 --- a/yudao-gateway/src/main/resources/application.yaml +++ b/yudao-gateway/src/main/resources/application.yaml @@ -177,6 +177,13 @@ spring: - Path=/admin-api/iot/** filters: - RewritePath=/admin-api/iot/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs + ## data-server 服务 + - id: data-admin-api # 路由的编号 + uri: grayLb://data-server + predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 + - Path=/admin-api/data/** + filters: + - RewritePath=/admin-api/data/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs x-forwarded: prefix-enabled: false # 避免 Swagger 重复带上额外的 /admin-api/system 前缀 @@ -234,6 +241,9 @@ knife4j: - name: iot-server service-name: iot-server url: /admin-api/iot/v3/api-docs + - name: data-server + service-name: data-server + url: /admin-api/data/v3/api-docs --- #################### 芋道相关配置 #################### diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java index 0b6675c0f..11100f98f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java @@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -61,6 +62,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti @Slf4j public class OAuth2OpenController { + @Qualifier("GXSKOAuth2GrantServiceImpl") @Resource private OAuth2GrantService oauth2GrantService; @Resource diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/GXSKOAuth2GrantServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/GXSKOAuth2GrantServiceImpl.java new file mode 100644 index 000000000..bcb4af7fd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/GXSKOAuth2GrantServiceImpl.java @@ -0,0 +1,109 @@ +package cn.iocoder.yudao.module.system.service.oauth2; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants; +import cn.iocoder.yudao.module.system.service.auth.AdminAuthService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + +/** + * OAuth2 授予 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class GXSKOAuth2GrantServiceImpl implements OAuth2GrantService { + + @Resource + private OAuth2TokenService oauth2TokenService; + @Resource + private OAuth2CodeService oauth2CodeService; + @Resource + private AdminAuthService adminAuthService; + + @Override + public OAuth2AccessTokenDO grantImplicit(Long userId, Integer userType, + String clientId, List scopes) { + return oauth2TokenService.createAccessToken(userId, userType, clientId, scopes); + } + + @Override + public String grantAuthorizationCodeForCode(Long userId, Integer userType, + String clientId, List scopes, + String redirectUri, String state) { + return oauth2CodeService.createAuthorizationCode(userId, userType, clientId, scopes, + redirectUri, state).getCode(); + } + + @Override + public OAuth2AccessTokenDO grantAuthorizationCodeForAccessToken(String clientId, String code, + String redirectUri, String state) { + OAuth2CodeDO codeDO = oauth2CodeService.consumeAuthorizationCode(code); + Assert.notNull(codeDO, "授权码不能为空"); // 防御性编程 + // 校验 clientId 是否匹配 + if (!StrUtil.equals(clientId, codeDO.getClientId())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_CLIENT_ID_MISMATCH); + } + // 校验 redirectUri 是否匹配 + if (!StrUtil.equals(redirectUri, codeDO.getRedirectUri())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_REDIRECT_URI_MISMATCH); + } + // 校验 state 是否匹配 + state = StrUtil.nullToDefault(state, ""); // 数据库 state 为 null 时,会设置为 "" 空串 + if (!StrUtil.equals(state, codeDO.getState())) { + throw exception(ErrorCodeConstants.OAUTH2_GRANT_STATE_MISMATCH); + } + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(codeDO.getUserId(), codeDO.getUserType(), + codeDO.getClientId(), codeDO.getScopes()); + } + + @Override + public OAuth2AccessTokenDO grantPassword(String username, String password, String clientId, List scopes) { + // 使用账号 + 密码进行登录 + AdminUserDO user = adminAuthService.authenticate(username, password); + Assert.notNull(user, "用户不能为空!"); // 防御性编程 + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(user.getId(), UserTypeEnum.ADMIN.getValue(), clientId, scopes); + } + + @Override + public OAuth2AccessTokenDO grantRefreshToken(String refreshToken, String clientId) { + return oauth2TokenService.refreshAccessToken(refreshToken, clientId); + } + + @Override + public OAuth2AccessTokenDO grantClientCredentials(String clientId, List scopes) { + // TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景 +// throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式"); + + // 创建访问令牌 + return oauth2TokenService.createAccessToken(IdUtil.getSnowflakeNextId(), UserTypeEnum.MEMBER.getValue(), + clientId, scopes); + } + + @Override + public boolean revokeToken(String clientId, String accessToken) { + // 先查询,保证 clientId 时匹配的 + OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.getAccessToken(accessToken); + if (accessTokenDO == null || ObjectUtil.notEqual(clientId, accessTokenDO.getClientId())) { + return false; + } + // 再删除 + return oauth2TokenService.removeAccessToken(accessToken) != null; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml b/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml index 061dfe04a..7e37fe956 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/application.yaml @@ -165,6 +165,7 @@ yudao: tenant: # 多租户相关配置项 enable: true ignore-urls: + - /admin-api/system/oauth2/token # - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 - /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号 - /admin-api/system/captcha/get-image # 获取图片验证码,和租户无关