refactor: 优化项目模块命名(简化、分类、统一)

This commit is contained in:
2024-10-30 23:01:54 +08:00
parent 9ecdeb52f6
commit c276e53a8e
346 changed files with 160 additions and 162 deletions

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>top.continew</groupId>
<artifactId>continew-plugin</artifactId>
<version>${revision}</version>
</parent>
<artifactId>continew-plugin-open</artifactId>
<description>能力开放插件包括应用管理、API开放授权、API开发等</description>
</project>

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.handler;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface;
import org.springframework.stereotype.Component;
import top.continew.admin.open.util.ApiSignCheckUtils;
import java.lang.reflect.Method;
import static cn.dev33.satoken.annotation.handler.SaCheckPermissionHandler._checkMethod;
/**
* 重定义注解 SaCheckPermission 的处理器
*
* @author chengzi
* @since 2024/10/25 12:03
*/
@Component
public class SaCheckPermissionHandler implements SaAnnotationHandlerInterface<SaCheckPermission> {
@Override
public Class<SaCheckPermission> getHandlerAnnotationClass() {
return SaCheckPermission.class;
}
@Override
public void checkMethod(SaCheckPermission at, Method method) {
if (!ApiSignCheckUtils.isExistSignParam()) {
_checkMethod(at.type(), at.value(), at.mode(), at.orRole());
}
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.mapper;
import top.continew.starter.data.mp.base.BaseMapper;
import top.continew.admin.open.model.entity.AppDO;
/**
* 应用 Mapper
*
* @author chengzi
* @since 2024/10/17 16:03
*/
public interface AppMapper extends BaseMapper<AppDO> {}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.entity;
import java.io.Serial;
import java.time.*;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
import top.continew.starter.extension.crud.model.entity.BaseDO;
/**
* 应用实体
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@TableName("sys_app")
public class AppDO extends BaseDO {
@Serial
private static final long serialVersionUID = 1L;
/**
* ID
*/
private Long id;
/**
* 应用名称
*/
private String name;
/**
* APPKEY
*/
private String appKey;
/**
* APPSECRET
*/
private String appSecret;
/**
* 应用状态
*/
private String status;
/**
* 失效时间
*/
private LocalDateTime expirationTime;
/**
* 应用描述
*/
private String appDesc;
/**
* secret查看状态
*/
private String secretStatus;
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.query;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import top.continew.starter.data.core.annotation.Query;
import top.continew.starter.data.core.enums.QueryType;
/**
* 应用查询条件
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@Schema(description = "应用查询条件")
public class AppQuery implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用名称
*/
@Schema(description = "应用名称")
@Query(type = QueryType.LIKE)
private String name;
/**
* APPKEY
*/
@Schema(description = "APPKEY")
@Query(type = QueryType.LIKE)
private String appKey;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.req;
import java.io.Serial;
import java.time.*;
import jakarta.validation.constraints.*;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
import top.continew.starter.extension.crud.model.req.BaseReq;
/**
* 创建或修改应用信息
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@Schema(description = "创建或修改应用信息")
public class AppReq extends BaseReq {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用名称
*/
@Schema(description = "应用名称")
@NotBlank(message = "应用名称不能为空")
@Length(max = 255, message = "应用名称长度不能超过 {max} 个字符")
private String name;
/**
* APPKEY
*/
@Schema(description = "应用密钥")
@NotBlank(message = "应用密钥不能为空")
@Length(max = 255, message = "应用密钥长度不能超过 {max} 个字符")
private String appKey;
/**
* 应用状态
*/
@Schema(description = "应用状态")
@NotBlank(message = "应用状态不能为空")
@Length(max = 255, message = "应用状态长度不能超过 {max} 个字符")
private String status;
/**
* 失效时间
*/
@Schema(description = "失效时间")
@NotNull(message = "失效时间不能为空")
private LocalDateTime expirationTime;
/**
* 应用描述
*/
@Schema(description = "应用描述")
@Length(max = 255, message = "应用描述长度不能超过 {max} 个字符")
private String appDesc;
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.resp;
import java.io.Serial;
import java.time.*;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import top.continew.starter.extension.crud.model.resp.BaseDetailResp;
/**
* 应用详情信息
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@ExcelIgnoreUnannotated
@Schema(description = "应用详情信息")
public class AppDetailResp extends BaseDetailResp {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用名称
*/
@Schema(description = "应用名称")
@ExcelProperty(value = "应用名称")
private String name;
/**
* 应用密钥
*/
@Schema(description = "应用密钥")
@ExcelProperty(value = "应用密钥")
private String appKey;
/**
* 应用状态
*/
@Schema(description = "应用状态")
@ExcelProperty(value = "应用状态")
private String status;
/**
* 失效时间
*/
@Schema(description = "失效时间")
@ExcelProperty(value = "失效时间")
private LocalDateTime expirationTime;
/**
* 应用描述
*/
@Schema(description = "应用描述")
@ExcelProperty(value = "应用描述")
private String appDesc;
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.resp;
import java.io.Serial;
import java.time.*;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import top.continew.starter.extension.crud.model.resp.BaseResp;
/**
* 应用信息
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@Schema(description = "应用信息")
public class AppResp extends BaseResp {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用名称
*/
@Schema(description = "应用名称")
private String name;
/**
* APPKEY
*/
@Schema(description = "应用密钥")
private String appKey;
/**
* 应用状态
*/
@Schema(description = "应用状态")
private String status;
/**
* 失效时间
*/
@Schema(description = "失效时间")
private LocalDateTime expirationTime;
/**
* 应用描述
*/
@Schema(description = "应用描述")
private String appDesc;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.model.resp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
/**
* 应用密钥/密码信息
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Data
@Schema(description = "应用密钥/密码信息")
public class AppSecretGetResp {
@Serial
private static final long serialVersionUID = 1L;
/**
* 应用密钥
*/
@Schema(description = "应用密钥")
private String appKey;
/**
* 应用密码
*/
@Schema(description = "应用密码")
private String appSecret;
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.service;
import top.continew.admin.open.model.resp.AppSecretGetResp;
import top.continew.starter.extension.crud.service.BaseService;
import top.continew.admin.open.model.query.AppQuery;
import top.continew.admin.open.model.req.AppReq;
import top.continew.admin.open.model.resp.AppDetailResp;
import top.continew.admin.open.model.resp.AppResp;
/**
* 应用业务接口
*
* @author chengzi
* @since 2024/10/17 16:03
*/
public interface AppService extends BaseService<AppResp, AppDetailResp, AppQuery, AppReq> {
/**
* 根据ID查询应用密码
*
* @param id ID
* @return 应用密码
*/
AppSecretGetResp getAppSecretById(Long id);
/**
* 根据ID重置应用密码查看状态
*
* @param id ID
*/
void resetAppSecretStatusById(Long id, String status);
/**
* 根据应用密钥重置应用密码查看状态
*
* @param appKey 应用密钥
*/
void resetAppSecretStatusByAppkey(String appKey, String status);
/**
* 根据ID刷新应用密码
*
* @param id ID
*/
void refreshAppSecretByID(Long id);
/**
* 根据应用密钥获取应用密码
*
* @param appKey 应用密钥
* @return 应用密码
*/
String getAppSecretByAppKey(String appKey);
/**
* 判断应用密钥是否存在
*
* @param appKey 应用密钥
* @return 是否存在true存在false不存在
*/
boolean isExistAppKey(String appKey);
/**
* 判断应用密钥是否过期
*
* @param appKey 应用密钥
* @return 是否过期true已过期false未过期
*/
boolean isExpireAppKey(String appKey);
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.continew.admin.open.model.resp.AppSecretGetResp;
import top.continew.starter.extension.crud.service.impl.BaseServiceImpl;
import top.continew.admin.open.mapper.AppMapper;
import top.continew.admin.open.model.entity.AppDO;
import top.continew.admin.open.model.query.AppQuery;
import top.continew.admin.open.model.req.AppReq;
import top.continew.admin.open.model.resp.AppDetailResp;
import top.continew.admin.open.model.resp.AppResp;
import top.continew.admin.open.service.AppService;
import java.time.LocalDateTime;
/**
* 应用业务实现
*
* @author chengzi
* @since 2024/10/17 16:03
*/
@Service
@RequiredArgsConstructor
public class AppServiceImpl extends BaseServiceImpl<AppMapper, AppDO, AppResp, AppDetailResp, AppQuery, AppReq> implements AppService {
// 已激活
private final static String APP_ENABLED_KEY = "1";
// 未激活
private final static String APP_DISABLED_KEY = "0";
@Override
public AppSecretGetResp getAppSecretById(Long id) {
AppDO app = baseMapper.lambdaQuery().eq(AppDO::getId, id).one();
String appSecret = "********";
if (app.getSecretStatus().equals(APP_DISABLED_KEY)) {
appSecret = app.getAppSecret();
this.resetAppSecretStatusById(id, APP_ENABLED_KEY);
}
AppSecretGetResp appSecretGetResp = new AppSecretGetResp();
appSecretGetResp.setAppKey(app.getAppKey());
appSecretGetResp.setAppSecret(appSecret);
return appSecretGetResp;
}
@Override
public void resetAppSecretStatusById(Long id, String status) {
baseMapper.lambdaUpdate().set(AppDO::getSecretStatus, status).eq(AppDO::getId, id).update();
}
@Override
public void resetAppSecretStatusByAppkey(String appKey, String status) {
baseMapper.lambdaUpdate().set(AppDO::getSecretStatus, status).eq(AppDO::getAppKey, appKey).update();
}
@Override
public void refreshAppSecretByID(Long id) {
baseMapper.lambdaUpdate().set(AppDO::getAppSecret, IdUtil.simpleUUID()).eq(AppDO::getId, id).update();
this.resetAppSecretStatusById(id, APP_DISABLED_KEY);
}
@Override
public String getAppSecretByAppKey(String appKey) {
return baseMapper.lambdaQuery().select(AppDO::getAppSecret).eq(AppDO::getAppKey, appKey).one().getAppSecret();
}
@Override
public boolean isExistAppKey(String appKey) {
return baseMapper.lambdaQuery().eq(AppDO::getAppKey, appKey).exists();
}
@Override
public boolean isExpireAppKey(String appKey) {
LocalDateTime expirationTime = baseMapper.lambdaQuery()
.select(AppDO::getExpirationTime)
.eq(AppDO::getAppKey, appKey)
.one()
.getExpirationTime();
return expirationTime.isBefore(LocalDateTimeUtil.of(DateUtil.date()));
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.sign;
import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaSignException;
import cn.dev33.satoken.sign.SaSignTemplate;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import top.continew.admin.open.service.AppService;
import java.util.Map;
import java.util.TreeMap;
import static cn.dev33.satoken.SaManager.log;
@Component
@RequiredArgsConstructor
public class OpenSignTemplate extends SaSignTemplate {
private final AppService appService;
public static String appKey = "appkey";
@Override
public void checkParamMap(Map<String, String> paramMap) {
// 获取必须的参数
String timestampValue = paramMap.get(timestamp);
String nonceValue = paramMap.get(nonce);
String signValue = paramMap.get(sign);
String appKeyValue = paramMap.get(appKey);
// 参数非空校验
SaSignException.notEmpty(timestampValue, "缺少 timestamp 字段");
SaSignException.notEmpty(nonceValue, "缺少 nonce 字段");
SaSignException.notEmpty(signValue, "缺少 sign 字段");
SaSignException.notEmpty(appKeyValue, "缺少 appkey 字段");
// 应用存在性校验
SaSignException.notTrue(!appService.isExistAppKey(appKeyValue), "应用不存在");
// 应用是否过期校验
SaSignException.notTrue(appService.isExpireAppKey(appKeyValue), "应用已过期");
// 依次校验三个参数
checkTimestamp(Long.parseLong(timestampValue));
checkNonce(nonceValue);
checkSign(paramMap, signValue);
// 通过 √
}
@Override
public String createSign(Map<String, ?> paramsMap) {
// 根据应用密钥获取对应的应用密码
String appKey = (String)((Map)paramsMap).get("appkey");
String secretKey = this.appService.getAppSecretByAppKey(appKey);
SaSignException.notEmpty(secretKey, "参与参数签名的秘钥不可为空", SaErrorCode.CODE_12201);
// 如果调用者不小心传入了 sign 参数,则此处需要将 sign 参数排除在外
if (paramsMap.containsKey(sign)) {
// 为了保证不影响原有的 paramsMap此处需要再复制一份
paramsMap = new TreeMap<>(paramsMap);
paramsMap.remove(sign);
}
// 计算签名
String paramsStr = joinParamsDictSort(paramsMap);
String fullStr = paramsStr + "&" + key + "=" + secretKey;
String signStr = abstractStr(fullStr);
// 输入日志,方便调试
log.debug("fullStr{}", fullStr);
log.debug("signStr{}", signStr);
// 返回
return signStr;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package top.continew.admin.open.util;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import java.util.List;
/**
* API签名验证工具类
*
* @author chengzi
* @since 2024/10/25 15:31
*/
public class ApiSignCheckUtils {
private ApiSignCheckUtils() {
}
/**
* 判断请求是否包含sign参数
*
* @return 是否包含sign参数true包含false不包含
*/
public static boolean isExistSignParam() {
SaRequest saRequest = SaHolder.getRequest();
List<String> paramNames = saRequest.getParamNames();
return paramNames.stream().anyMatch(paramName -> paramName.equals("sign"));
}
}