Compare commits

..

5 Commits

Author SHA1 Message Date
kongxz
3018c9b1ab 流程引擎 2026-07-06 11:32:36 +08:00
xuyanbo
f4221236fb feat(架构): 修改为k8s内部地址 2026-07-06 11:32:30 +08:00
刘雅馨
7475f9d75d 主服务增加fegin接口调用 2026-07-06 11:32:26 +08:00
xuyanbo
045214ae80 doc(文档): 补充密钥 2026-07-06 11:32:26 +08:00
xuyanbo
475422d815 feat(20260506新版bladex): 项目init 2026-07-06 11:32:19 +08:00
1137 changed files with 178935 additions and 90 deletions

43
README.md Normal file
View File

@ -0,0 +1,43 @@
## 版权声明
* BladeX是一个商业化软件系列产品知识产权归**上海布雷德科技有限公司**独立所有
* 您一旦开始复制、下载、安装或者使用本产品,即被视为完全理解并接受本协议的各项条款
* 更多详情请看:[BladeX商业授权许可协议](https://license.bladex.cn)
## 答疑流程
>1. 遇到问题或Bug
>2. 业务型问题打断点调试尝试找出问题所在
>3. 系统型问题通过百度、谷歌、社区查找解决方案
>4. 未解决问题则进入技术社区进行发帖提问:[https://sns.bladex.cn](https://sns.bladex.cn)
>5. 将帖子地址发至商业群,特别简单三言两语就能描述清楚的也可在答疑时间内发至商业群提问
>6. 发帖的时候一定要描述清楚,详细描述遇到问题的**重现步骤**、**报错详细信息**、**相关代码与逻辑**、**使用软件版本**以及**操作系统版本**,否则随意发帖提问将会提高我们的答疑难度。
## 答疑时间
* 工作日9:00 ~ 17:00 提供答疑,周末、节假日休息,暂停答疑
* 请勿**私聊提问**,以免被其他用户的消息覆盖从而无法获得答疑
* 答疑时间外遇到问题可以将问题发帖至[技术社区](https://sns.bladex.cn),我们后续会逐个回复
## 授权范围
* 专业版:只可用于**个人学习**及**个人私活**项目,不可用于公司或团队,不可泄露给任何第三方
* 企业版:可用于**企业名下**的任何项目,企业版员工在**未购买**专业版授权前,只授权开发**所在授权企业名下**的项目,**不得将BladeX用于个人私活**
* 共同遵守若甲方需要您提供项目源码则需代为甲方购买BladeX企业授权甲方购买后续的所有项目都无需再次购买授权
## 商用权益
* ✔️ 遵守[商业协议](https://license.bladex.cn)的前提下将BladeX系列产品用于授权范围内的商用项目并上线运营
* ✔️ 遵守[商业协议](https://license.bladex.cn)的前提下,不限制项目数,不限制服务器数
* ✔️ 遵守[商业协议](https://license.bladex.cn)的前提下,将自行编写的业务代码申请软件著作权
## 何为侵权
* ❌ 不遵守商业协议,私自销售商业源码
* ❌ 以任何理由将BladeX源码用于申请软件著作权
* ❌ 将商业源码以任何途径任何理由泄露给未授权的单位或个人
* ❌ 开发完毕项目没有为甲方购买企业授权向甲方提供了BladeX代码
* ❌ 基于BladeX拓展研发与BladeX有竞争关系的衍生框架并将其开源或销售
## 侵权后果
* 情节较轻:第一次发现警告处理
* 情节较重:封禁账号,踢出商业群,并保留追究法律责任的权利
* 情节严重:与本地律师事务所合作,以公司名义起诉侵犯计算机软件著作权
## 举报有奖
* 向官方提供有用线索并成功捣毁盗版个人或窝点,将会看成果给予 50010000 不等的现金奖励
* 官方唯一指定QQ1272154962

17
blade-auth/Dockerfile Normal file
View File

@ -0,0 +1,17 @@
# 网络问题无法下载可以改为阿里云镜像
# FROM registry.cn-hangzhou.aliyuncs.com/bladex-repo/alpine-java:openjdk17_cn_slim
FROM bladex/alpine-java:openjdk17_cn_slim
LABEL maintainer="bladejava@qq.com"
RUN mkdir -p /blade/auth
WORKDIR /blade/auth
EXPOSE 8100
COPY ./target/blade-auth.jar ./app.jar
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]

32
blade-auth/README.md Normal file
View File

@ -0,0 +1,32 @@
## 目前主要支持的oauth协议
一、 授权码模式
授权码模式(authorization_code)主要针对第三方应用,是最为复杂也最为安全的一种模式,操作步骤如下
1. 访问地址http://localhost:8100/oauth/authorize?client_id=blade&redirect_uri=http://example.com&code=233333&response_type=code
2. 获取跳转后的code值(http://example.com/?code=VhYNLR)之后,调用 http://localhost/blade-auth/oauth/token 传入对应的参数
请求头:
Authorization Basic YmxhZGU6YmxhZGU= "YmxhZGU6YmxhZGU="为clientId:clientSecret串转换为的base64编码
表单:
grant_typeauthorization_code
scopeall
codeVhYNLR
redirect_uri http://example.com
二、 密码模式
密码模式(password)主要针对自家应用,可信度较高,所以可以使用简便安全共存的模式,操作步骤如下
1. 直接调用 http://localhost/blade-auth/oauth/token 传入对应的参数
请求头:
Authorization Basic YmxhZGU6YmxhZGU= "YmxhZGU6YmxhZGU="为clientId:clientSecret串转换为的base64编码
表单:
grant_typepassword
scopeall
usernameadmin
password123456
## 获取到token后如何获取用户信息
1. 拼接请求头
Authorization bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCIsInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsiYWxsIl0sImV4cCI6MTU1MzE2MTA5NSwiYXV0aG9yaXRpZXMiOlsiUk9MRV9VU0VSIl0sImp0aSI6IjE0YmMyYjAyLTgxY2UtNDFiNC04ZTI3LTA5YWE0ZmU4ZWMwYyIsImNsaWVudF9pZCI6ImJsYWRlIn0.jTmioQDq-fSNNn7YCwl3wP0JE-etSWtzLDe545mDbP4
2. 调用 http://localhost/blade-auth/oauth/user-info 既可获得对应用户信息

103
blade-auth/pom.xml Normal file
View File

@ -0,0 +1,103 @@
<?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>
<artifactId>BladeX</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<artifactId>blade-auth</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<!--Blade-->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId>
<exclusions>
<exclusion>
<groupId>org.springblade</groupId>
<artifactId>blade-scope-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-db</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-metrics</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-log</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-social</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-user-api</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-system-api</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-resource-api</artifactId>
</dependency>
<!--安全模块-->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-oauth2</artifactId>
</dependency>
<!-- 验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
</dependency>
<!-- 链路追踪、服务监控 -->
<!--<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-trace</artifactId>
</dependency>-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>${docker.fabric.skip}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,47 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth;
import org.springblade.core.cloud.client.BladeCloudApplication;
import org.springblade.core.launch.BladeApplication;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
/**
* 用户认证服务器
*
* @author Chill
*/
@EnableRedisHttpSession
@BladeCloudApplication
public class AuthApplication {
public static void main(String[] args) {
BladeApplication.run(AppConstant.APPLICATION_AUTH_NAME, AuthApplication.class, args);
}
}

View File

@ -0,0 +1,101 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.config;
import org.springblade.auth.handler.BladeAuthorizationHandler;
import org.springblade.auth.handler.BladeLockHandler;
import org.springblade.auth.handler.BladeLogHandler;
import org.springblade.auth.handler.BladePasswordHandler;
import org.springblade.auth.handler.BladeTokenHandler;
import org.springblade.auth.service.BladeClientDetailService;
import org.springblade.auth.service.BladeUserDetailService;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.oauth2.config.OAuth2AutoConfiguration;
import org.springblade.core.oauth2.handler.AuthorizationHandler;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.handler.TokenHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.system.feign.IAuthLockClient;
import org.springblade.system.feign.IAuthLogClient;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.system.feign.IUserClient;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* BladeAuthConfiguration
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(OAuth2AutoConfiguration.class)
public class BladeAuthConfiguration {
@Bean
public AuthorizationHandler authorizationHandler(BladeProperties bladeProperties,
BladeTenantProperties tenantProperties,
OAuth2Properties oAuth2Properties,
BladeLockHandler lockHandler,
BladeLogHandler logHandler) {
return new BladeAuthorizationHandler(bladeProperties, tenantProperties, oAuth2Properties, lockHandler, logHandler);
}
@Bean
public BladeLockHandler lockHandler(IAuthLockClient authLockClient) {
return new BladeLockHandler(authLockClient);
}
@Bean
public BladeLogHandler logHandler(IAuthLogClient authLogClient, BladeProperties bladeProperties, ServerInfo serverInfo) {
return new BladeLogHandler(authLogClient, bladeProperties, serverInfo);
}
@Bean
public PasswordHandler passwordHandler(OAuth2Properties properties) {
return new BladePasswordHandler(properties);
}
@Bean
public TokenHandler tokenHandler(JwtProperties jwtProperties) {
return new BladeTokenHandler(jwtProperties);
}
@Bean
public OAuth2ClientService oAuth2ClientService(JdbcTemplate jdbcTemplate) {
return new BladeClientDetailService(jdbcTemplate);
}
@Bean
public OAuth2UserService oAuth2UserService(IUserClient userClient) {
return new BladeUserDetailService(userClient);
}
}

View File

@ -0,0 +1,35 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.constant;
/**
* AuthorizationConstant
*
* @author Chill
*/
public interface BladeAuthConstant {
}

View File

@ -0,0 +1,98 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.endpoint;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.core.oauth2.props.OAuth2Properties;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.resource.feign.ISmsClient;
import org.springblade.resource.utils.SmsUtil;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static org.springblade.core.oauth2.constant.OAuth2TokenConstant.USER_PHONE_NOT_FOUND;
/**
* Oauth2SmsEndpoint
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@Tag(name = "用户短信认证", description = "4 - OAuth2短信认证端点")
public class Oauth2SmsEndpoint {
/**
* 短信服务构建类
*/
private final ISmsClient smsClient;
/**
* 用户服务类
*/
private final OAuth2UserService userService;
/**
* OAuth2配置类
*/
private final OAuth2Properties properties;
/**
* 短信验证码发送
*
* @param tenantId 租户ID
* @param phone 手机号
*/
@SneakyThrows
@PostMapping("/oauth/sms/send-validate")
public R sendValidate(@RequestParam String tenantId, @RequestParam String phone) {
// 校验手机加密认证防止恶意发送验证码
String decryptedPhone = SM2Util.decrypt(phone, properties.getPublicKey(), properties.getPrivateKey());
if (StringUtil.isBlank(decryptedPhone)) {
return R.fail(USER_PHONE_NOT_FOUND);
}
// 校验手机是否已注册防止恶意发送验证码
OAuth2Request request = OAuth2Request.create();
request.setTenantId(tenantId);
OAuth2User oAuth2User = userService.loadByPhone(decryptedPhone, request);
if (oAuth2User == null) {
return R.fail(USER_PHONE_NOT_FOUND);
}
// 用户存在则发送验证码
R result = smsClient.sendValidate(tenantId, StringPool.EMPTY, decryptedPhone);
return result.isSuccess() ? R.data(result.getData(), SmsUtil.SEND_SUCCESS) : R.fail(SmsUtil.SEND_FAIL);
}
}

View File

@ -0,0 +1,73 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.granter;
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.PasswordTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.stereotype.Component;
/**
* CaptchaTokenGranter
*
* @author BladeX
*/
@Component
public class CaptchaTokenGranter extends PasswordTokenGranter {
private final BladeRedis bladeRedis;
public CaptchaTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, BladeRedis bladeRedis) {
super(clientService, userService, passwordHandler);
this.bladeRedis = bladeRedis;
}
@Override
public String type() {
return CAPTCHA;
}
@Override
public OAuth2User user(OAuth2Request request) {
// 获取验证码信息
String key = request.getCaptchaKey();
String code = request.getCaptchaCode();
// 获取验证码
String redisCode = bladeRedis.getAndDel(OAuth2TokenConstant.CAPTCHA_CACHE_KEY + key);
// 判断验证码
if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
}
return super.user(request);
}
}

View File

@ -0,0 +1,161 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.granter;
import org.jetbrains.annotations.NotNull;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.provider.OAuth2Token;
import org.springblade.core.oauth2.service.OAuth2Client;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.NumberUtil;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.system.cache.ParamCache;
import org.springblade.system.feign.IUserClient;
import org.springblade.system.pojo.entity.User;
import org.springblade.system.pojo.enums.UserType;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.function.Predicate;
import static org.springblade.common.constant.ParamConstant.REGISTER_USER_VALUE;
/**
* RegisterTokenGranter
*
* @author BladeX
*/
@Component
public class RegisterTokenGranter extends AbstractTokenGranter {
private final IUserClient userClient;
private final OAuth2Properties properties;
public RegisterTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, IUserClient userClient, OAuth2Properties properties) {
super(clientService, userService, passwordHandler);
this.userClient = userClient;
this.properties = properties;
}
@Override
public String type() {
return REGISTER;
}
@Override
public OAuth2User user(OAuth2Request request) {
// 校验注册功能是否开启
Boolean registerOpen = Func.toBoolean(ParamCache.getValue(REGISTER_USER_VALUE), false);
if (!registerOpen) {
throw new UserInvalidException("注册功能暂未开启,请联系管理员");
}
// 用户注册信息
User user = new User();
user.setUserType(UserType.of(request.getUserType()).getCategory());
user.setTenantId(request.getTenantId());
user.setAccount(request.getUsername());
user.setPassword(SM2Util.decrypt(request.getPassword(), properties.getPublicKey(), properties.getPrivateKey()));
user.setName(request.getName());
user.setRealName(request.getName());
user.setPhone(request.getPhone());
user.setEmail(request.getEmail());
// 校验用户格式
validateUser(user);
R<String> result = userClient.registerUser(user);
// 执行用户注册
if (result.isSuccess()) {
// 构建oauth2所需用户信息
user.setId(NumberUtil.toLong(result.getData()));
return convertOAuth2UserDetail(user, client(request));
}
throw new UserInvalidException(result.getMsg());
}
@Override
public OAuth2Token token(OAuth2User user, OAuth2Request request) {
// 移除注册后返回的令牌与刷新令牌防止外部攻击采用注册接口获取令牌并调用低权接口
// 注意
// 1. 框架已默认开启严格模式blade.secure.strict-token=true不移除令牌则不受影响注册令牌会被框架校验并拒绝
// 2. 若自行关闭严格模式blade.secure.strict-token=false必须将令牌移除否则注册获取令牌后可调用低权接口
OAuth2Token token = super.token(user, request);
token.getArgs().remove(TokenConstant.ACCESS_TOKEN);
token.getArgs().remove(TokenConstant.REFRESH_TOKEN);
return token;
}
private void validateUser(User user) {
Predicate<String> isNameValid = name -> name.matches("^([\\u4e00-\\u9fa5]{2,20}|[a-zA-Z]{2,10})$");
Predicate<String> isUsernameValid = username -> username.matches("^(?=.*[a-zA-Z])[a-zA-Z0-9_\\-@]{3,20}$");
Predicate<String> isPasswordValid = password -> password.matches("^(?=.*[0-9])(?=.*[a-zA-Z])[\\w@-]{6,20}$");
Predicate<String> isPhoneValid = phone -> phone.matches("^1[3-9]\\d{9}$");
Predicate<String> isEmailValid = email -> email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
if (!isNameValid.test(user.getName())) {
throw new UserInvalidException("用户姓名长度必须在2-10之间且仅能设置纯中文或纯英文");
}
if (!isUsernameValid.test(user.getAccount())) {
throw new UserInvalidException("用户账号长度必须在3-20之间且需要包含英文可额外携带数字、下划线、横杠、@");
}
if (!isPasswordValid.test(user.getPassword())) {
throw new UserInvalidException("用户密码长度必须在6-20之间且需要包含英文与数字可额外携带下划线、横杠、@");
}
if (!isPhoneValid.test(user.getPhone())) {
throw new UserInvalidException("手机号格式不正确");
}
if (!isEmailValid.test(user.getEmail())) {
throw new UserInvalidException("邮箱格式不正确");
}
}
@NotNull
private OAuth2UserDetail convertOAuth2UserDetail(User user, OAuth2Client client) {
OAuth2UserDetail userDetail = new OAuth2UserDetail();
userDetail.setUserId(String.valueOf(user.getId()));
userDetail.setTenantId(user.getTenantId());
userDetail.setName(user.getName());
userDetail.setRealName(user.getName());
userDetail.setAccount(user.getAccount());
userDetail.setPassword(user.getPassword());
userDetail.setPhone(user.getPhone());
userDetail.setEmail(user.getEmail());
userDetail.setAuthorities(Collections.singletonList(REGISTER));
userDetail.setClient(client);
return userDetail;
}
}

View File

@ -0,0 +1,103 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.granter;
import jakarta.servlet.http.HttpServletRequest;
import org.springblade.core.oauth2.constant.OAuth2TokenConstant;
import org.springblade.core.oauth2.exception.UserInvalidException;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.sms.model.SmsCode;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.resource.feign.ISmsClient;
import org.springframework.stereotype.Component;
/**
* SmsTokenGranter
*
* @author BladeX
*/
@Component
public class SmsTokenGranter extends AbstractTokenGranter {
private final OAuth2UserService userService;
private final ISmsClient smsClient;
private final OAuth2Properties properties;
public SmsTokenGranter(OAuth2ClientService clientService, OAuth2UserService userService, PasswordHandler passwordHandler, ISmsClient smsClient, OAuth2Properties properties) {
super(clientService, userService, passwordHandler);
this.userService = userService;
this.smsClient = smsClient;
this.properties = properties;
}
@Override
public String type() {
return SMS_CODE;
}
@Override
public OAuth2User user(OAuth2Request request) {
// 获取基础信息
String tenantId = request.getTenantId();
SmsCode smsCode = buildSmsCode();
// 校验手机加密认证
String decryptedPhone = SM2Util.decrypt(smsCode.getPhone(), properties.getPublicKey(), properties.getPrivateKey());
if (StringUtil.isBlank(decryptedPhone)) {
throw new UserInvalidException(OAuth2TokenConstant.USER_PHONE_NOT_FOUND);
}
// 获取短信验证信息
R result = smsClient.validateMessage(tenantId, StringPool.EMPTY, smsCode.getId(), smsCode.getValue(), decryptedPhone);
if (!result.isSuccess()) {
throw new UserInvalidException(OAuth2TokenConstant.CAPTCHA_NOT_CORRECT);
}
// 获取用户信息
OAuth2User user = userService.loadByPhone(decryptedPhone, request);
// 校验用户信息
if (!userService.validateUser(user)) {
throw new UserInvalidException(OAuth2TokenConstant.TOKEN_NOT_CORRECT);
}
// 设置客户端信息
user.setClient(client(request));
return user;
}
private SmsCode buildSmsCode() {
HttpServletRequest request = WebUtil.getRequest();
return new SmsCode().setId(request.getParameter("id"))
.setPhone(request.getParameter("phone"))
.setValue(request.getParameter("value"));
}
}

View File

@ -0,0 +1,120 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.granter;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
import org.springblade.core.oauth2.granter.AbstractTokenGranter;
import org.springblade.core.oauth2.handler.PasswordHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2ClientService;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
import org.springblade.core.social.props.SocialProperties;
import org.springblade.core.social.utils.SocialUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.system.pojo.entity.UserInfo;
import org.springblade.system.pojo.entity.UserOauth;
import org.springblade.system.feign.IUserClient;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* SocialTokenGranter
*
* @author Chill
*/
@Component
public class SocialTokenGranter extends AbstractTokenGranter {
private static final Integer AUTH_SUCCESS_CODE = 2000;
private final IUserClient userClient;
private final SocialProperties socialProperties;
public SocialTokenGranter(OAuth2ClientService clientService, OAuth2UserService oAuth2UserService, PasswordHandler passwordHandler, IUserClient userClient, SocialProperties socialProperties) {
super(clientService, oAuth2UserService, passwordHandler);
this.userClient = userClient;
this.socialProperties = socialProperties;
}
@Override
public String type() {
return SOCIAL;
}
@Override
public OAuth2User user(OAuth2Request request) {
String tenantId = request.getTenantId();
// 开放平台来源
String sourceParameter = request.getSource();
// 匹配是否有别名定义
String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
// 开放平台授权码
String code = request.getCode();
// 开放平台状态吗
String state = request.getState();
// 获取开放平台授权数据
AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
AuthCallback authCallback = new AuthCallback();
authCallback.setCode(code);
authCallback.setState(state);
AuthResponse<?> authResponse = authRequest.login(authCallback);
AuthUser authUser = null;
if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
authUser = (AuthUser) authResponse.getData();
} else {
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
}
// 组装数据
UserOauth userOauth = Objects.requireNonNull(BeanUtil.copyProperties(authUser, UserOauth.class));
userOauth.setSource(authUser.getSource());
userOauth.setTenantId(tenantId);
userOauth.setUuid(authUser.getUuid());
R<UserInfo> result = userClient.userAuthInfo(userOauth);
if (!result.isSuccess()) {
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
}
// 设置Oauth2用户信息
OAuth2User user = TokenUtil.convertUser(result.getData(), request);
// 设置客户端信息
user.setClient(client(request));
return user;
}
}

View File

@ -0,0 +1,200 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.handler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.TenantConstant;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.oauth2.exception.ExceptionCode;
import org.springblade.core.oauth2.handler.AbstractAuthorizationHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.provider.OAuth2Validation;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.tenant.BladeTenantProperties;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.system.cache.SysCache;
import org.springblade.system.pojo.entity.Tenant;
import java.util.Date;
import java.util.List;
/**
* BladeAuthorizationHandler
*
* @author BladeX
*/
@Slf4j
@RequiredArgsConstructor
public class BladeAuthorizationHandler extends AbstractAuthorizationHandler {
private final BladeProperties bladeProperties;
private final BladeTenantProperties tenantProperties;
private final OAuth2Properties oAuth2Properties;
private final BladeLockHandler lockHandler;
private final BladeLogHandler logHandler;
/**
* 自定义弱密码列表
*/
private static final List<String> WEAK_PASSWORDS = List.of("admin", "hr", "manager", "boss");
/**
* 认证前校验
*
* @param request 请求信息
* @return boolean
*/
@Override
public OAuth2Validation preValidation(OAuth2Request request) {
if (request.isPassword() || request.isCaptchaCode()) {
// 生产环境弱密码校验
if (bladeProperties.isProd() && isWeakPassword(request.getPassword())) {
return buildValidationFailure(ExceptionCode.INVALID_USER_PASSWORD);
}
// 判断账号是否锁定
OAuth2Validation accountValidation = lockHandler.validateAccountLock(request.getTenantId(), request.getUsername());
if (!accountValidation.isSuccess()) {
return accountValidation;
}
// 判断IP是否锁定
OAuth2Validation ipValidation = lockHandler.validateIpLock(request.getTenantId());
if (!ipValidation.isSuccess()) {
return ipValidation;
}
}
return super.preValidation(request);
}
/**
* 认证前失败回调
*
* @param validation 失败信息
*/
@Override
public void preFailure(OAuth2Request request, OAuth2Validation validation) {
// 处理认证失败增加错误次数
lockHandler.handleAuthFailure(request.getTenantId(), request.getUsername());
log.error("用户:{},认证失败,失败原因:{}", request.getUsername(), validation.getMessage());
}
/**
* 认证校验
*
* @param user 用户信息
* @param request 请求信息
* @return boolean
*/
@Override
public OAuth2Validation authValidation(OAuth2User user, OAuth2Request request) {
// 密码模式刷新token模式验证码模式需要校验租户状态
if (request.isPassword() || request.isRefreshToken() || request.isCaptchaCode()) {
// 租户校验
OAuth2Validation tenantValidation = validateTenant(user.getTenantId());
if (!tenantValidation.isSuccess()) {
return tenantValidation;
}
}
return super.authValidation(user, request);
}
/**
* 认证成功回调
*
* @param user 用户信息
*/
@Override
public void authSuccessful(OAuth2User user, OAuth2Request request) {
// 处理认证成功清空错误次数
lockHandler.handleAuthSuccess(user.getTenantId(), user.getAccount());
// 记录认证成功日志
logHandler.handleAuthLog(user, request);
log.info("用户:{},认证成功", user.getAccount());
}
/**
* 认证失败回调
*
* @param user 用户信息
* @param validation 失败信息
*/
@Override
public void authFailure(OAuth2User user, OAuth2Request request, OAuth2Validation validation) {
// 自定义认证失败回调
}
/**
* 判断是否为弱密码
*
* @param rawPassword 加密密码
* @return boolean
*/
private boolean isWeakPassword(String rawPassword) {
// 获取公钥
String publicKey = oAuth2Properties.getPublicKey();
// 获取私钥
String privateKey = oAuth2Properties.getPrivateKey();
// 解密密码
String decryptPassword = SM2Util.decrypt(rawPassword, publicKey, privateKey);
return WEAK_PASSWORDS.stream()
.anyMatch(weakPass -> weakPass.equalsIgnoreCase(decryptPassword));
}
/**
* 租户授权校验
*
* @param tenantId 租户id
* @return OAuth2Validation
*/
private OAuth2Validation validateTenant(String tenantId) {
// 租户校验
Tenant tenant = SysCache.getTenant(tenantId);
if (tenant == null) {
return buildValidationFailure(ExceptionCode.USER_TENANT_NOT_FOUND);
}
// 租户授权时间校验
Date expireTime = tenant.getExpireTime();
if (tenantProperties.getLicense()) {
String licenseKey = tenant.getLicenseKey();
String decrypt = DesUtil.decryptFormHex(licenseKey, TenantConstant.DES_KEY);
Tenant license = JsonUtil.parse(decrypt, Tenant.class);
if (license == null || !license.getId().equals(tenant.getId())) {
return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
}
expireTime = license.getExpireTime();
}
if (expireTime != null && expireTime.before(DateUtil.now())) {
return buildValidationFailure(ExceptionCode.UNAUTHORIZED_USER_TENANT);
}
return new OAuth2Validation();
}
}

View File

@ -0,0 +1,155 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.handler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.oauth2.exception.ExceptionCode;
import org.springblade.core.oauth2.provider.OAuth2Validation;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.feign.IAuthLockClient;
import java.util.concurrent.CompletableFuture;
/**
* 失败锁定处理器
* 统一管理账号锁定和IP锁定逻辑
*
* @author BladeX
*/
@Slf4j
@RequiredArgsConstructor
public class BladeLockHandler {
private final IAuthLockClient authLockClient;
/**
* 校验账号是否锁定
*
* @param tenantId 租户id
* @param account 账号
* @return OAuth2Validation
*/
public OAuth2Validation validateAccountLock(String tenantId, String account) {
try {
R<Boolean> result = authLockClient.isAccountLocked(tenantId, account);
if (result.isSuccess() && Boolean.TRUE.equals(result.getData())) {
log.error("用户:{}已锁定请求ip{}", account, WebUtil.getIP());
return buildValidationFailure();
}
} catch (Exception e) {
log.warn("账号锁定校验异常: {}", e.getMessage());
}
return new OAuth2Validation();
}
/**
* 校验IP是否锁定
*
* @param tenantId 租户id
* @return OAuth2Validation
*/
public OAuth2Validation validateIpLock(String tenantId) {
String clientIp = WebUtil.getIP();
try {
R<Boolean> result = authLockClient.isIpLocked(tenantId, clientIp);
if (result.isSuccess() && Boolean.TRUE.equals(result.getData())) {
log.error("IP{},已锁定", clientIp);
return buildValidationFailure();
}
} catch (Exception e) {
log.warn("IP锁定校验异常: {}", e.getMessage());
}
return new OAuth2Validation();
}
/**
* 处理认证失败
* 同时增加账号和IP错误次数
*
* @param tenantId 租户id
* @param account 账号
* @param userId 用户ID
*/
public void handleAuthFailure(String tenantId, String account, Long userId) {
String ip = WebUtil.getIP();
String userAgent = WebUtil.getUserAgent();
CompletableFuture.runAsync(() -> {
try {
authLockClient.addAccountFailCount(tenantId, account, userId, ip, userAgent);
authLockClient.addIpFailCount(tenantId, ip, userAgent);
} catch (Exception e) {
log.warn("认证失败计数异常: {}", e.getMessage());
}
});
}
/**
* 处理认证失败
* 同时增加账号和IP错误次数
*
* @param tenantId 租户id
* @param account 账号
*/
public void handleAuthFailure(String tenantId, String account) {
handleAuthFailure(tenantId, account, null);
}
/**
* 处理认证成功
* 释放系统自动锁定
*
* @param tenantId 租户id
* @param account 账号
*/
public void handleAuthSuccess(String tenantId, String account) {
String ip = WebUtil.getIP();
CompletableFuture.runAsync(() -> {
try {
authLockClient.releaseSystemLock(tenantId, account);
authLockClient.releaseSystemIpLock(tenantId, ip);
} catch (Exception e) {
log.warn("认证成功释放锁定异常: {}", e.getMessage());
}
});
}
/**
* 构建校验失败结果
*
* @return OAuth2Validation
*/
private OAuth2Validation buildValidationFailure() {
OAuth2Validation validation = new OAuth2Validation();
validation.setSuccess(false);
validation.setCode(ExceptionCode.USER_TOO_MANY_FAILS.getCode());
validation.setMessage(ExceptionCode.USER_TOO_MANY_FAILS.getMessage());
return validation;
}
}

View File

@ -0,0 +1,99 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.handler;
import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.WebUtil;
import org.springblade.system.pojo.entity.AuthLog;
import org.springblade.system.feign.IAuthLogClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CompletableFuture;
/**
* 认证日志处理器
* 在用户认证成功时异步记录登录日志
*
* @author BladeX
*/
@Slf4j
@RequiredArgsConstructor
public class BladeLogHandler {
private final IAuthLogClient authLogClient;
private final BladeProperties bladeProperties;
private final ServerInfo serverInfo;
/**
* 记录认证成功日志
*
* @param user 用户信息
* @param request 请求信息
*/
public void handleAuthLog(OAuth2User user, OAuth2Request request) {
// 异步记录日志避免影响认证性能
CompletableFuture.runAsync(() -> {
try {
AuthLog authLog = buildAuthLog(user, request);
authLogClient.saveAuthLog(authLog);
} catch (Exception exception) {
log.error("记录认证日志异常:{}", exception.getMessage(), exception);
}
});
}
/**
* 构建认证日志实体
*
* @param user 用户信息
* @param request 请求信息
* @return AuthLog
*/
private AuthLog buildAuthLog(OAuth2User user, OAuth2Request request) {
AuthLog authLog = new AuthLog();
authLog.setUserId(Func.toLong(user.getUserId()));
authLog.setTenantId(user.getTenantId());
authLog.setServiceId(bladeProperties.getName());
authLog.setServerIp(serverInfo.getIpWithPort());
authLog.setServerHost(serverInfo.getHostName());
authLog.setEnv(bladeProperties.getEnv());
authLog.setAccount(user.getAccount());
authLog.setRealName(user.getRealName());
authLog.setGrantType(request.getGrantType());
authLog.setRemoteIp(WebUtil.getIP(request.getHttpRequest()));
authLog.setUserAgent(WebUtil.getUserAgent(request.getHttpRequest()));
authLog.setLoginTime(DateUtil.now());
return authLog;
}
}

View File

@ -0,0 +1,64 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.handler;
import org.springblade.core.oauth2.handler.OAuth2PasswordHandler;
import org.springblade.core.oauth2.props.OAuth2Properties;
/**
* BladePasswordHandler
*
* @author BladeX
*/
public class BladePasswordHandler extends OAuth2PasswordHandler {
public BladePasswordHandler(OAuth2Properties properties) {
super(properties);
}
/**
* 判断密码是否匹配
*
* @param rawPassword 请求时提交的原密码
* @param encodedPassword 数据库加密后的密码
* @return boolean
*/
@Override
public boolean matches(String rawPassword, String encodedPassword) {
return super.matches(rawPassword, encodedPassword);
}
/**
* 加密密码规则
*
* @param rawPassword 密码
* @return 加密后的密码
*/
@Override
public String encode(String rawPassword) {
return super.encode(rawPassword);
}
}

View File

@ -0,0 +1,59 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.handler;
import org.springblade.core.jwt.props.JwtProperties;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.oauth2.handler.OAuth2TokenHandler;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.provider.OAuth2Token;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.tool.support.Kv;
/**
* BladeTokenHandler
*
* @author BladeX
*/
public class BladeTokenHandler extends OAuth2TokenHandler {
public BladeTokenHandler(JwtProperties properties) {
super(properties);
}
@Override
public OAuth2Token enhance(OAuth2User user, OAuth2Token token, OAuth2Request request) {
// 父类令牌状态配置
OAuth2Token enhanceToken = super.enhance(user, token, request);
// 令牌统一处理增加或删减字段
Kv args = enhanceToken.getArgs();
args.set(TokenConstant.USER_NAME, user.getAccount());
// 返回令牌
return enhanceToken;
}
}

View File

@ -0,0 +1,62 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.service;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2Client;
import org.springblade.core.oauth2.service.impl.OAuth2ClientDetailService;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* BladeClientDetailService
*
* @author Chill
*/
public class BladeClientDetailService extends OAuth2ClientDetailService {
public BladeClientDetailService(JdbcTemplate jdbcTemplate) {
super(jdbcTemplate);
}
@Override
public OAuth2Client loadByClientId(String clientId) {
return super.loadByClientId(clientId);
}
@Override
public OAuth2Client loadByClientId(String clientId, OAuth2Request request) {
return super.loadByClientId(clientId, request);
}
@Override
public boolean validateClient(OAuth2Client client, String clientId, String clientSecret) {
return super.validateClient(client, clientId, clientSecret);
}
@Override
public boolean validateGranter(OAuth2Client client, String grantType) {
return super.validateGranter(client, grantType);
}
}

View File

@ -0,0 +1,111 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.service;
import lombok.RequiredArgsConstructor;
import org.springblade.auth.utils.TokenUtil;
import org.springblade.core.oauth2.exception.OAuth2ErrorCode;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.OAuth2UserService;
import org.springblade.core.oauth2.utils.OAuth2ExceptionUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.system.feign.IUserClient;
import org.springblade.system.pojo.entity.UserInfo;
import org.springblade.system.pojo.enums.UserType;
import java.util.Optional;
/**
* BladeUserDetailService
*
* @author Chill
*/
@RequiredArgsConstructor
public class BladeUserDetailService implements OAuth2UserService {
private final IUserClient userClient;
@Override
public OAuth2User loadByUserId(String userId, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
// 获取用户信息
R<UserInfo> result = userClient.userInfo(Func.toLong(userId), userType);
if (!result.isSuccess()) {
OAuth2ExceptionUtil.throwFromCode(OAuth2ErrorCode.INVALID_USER);
}
// 构建oauth2用户信息
return TokenUtil.convertUser(result.getData(), request);
}
@Override
public OAuth2User loadByUsername(String username, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
String tenantId = request.getTenantId();
// 获取用户信息
R<UserInfo> result = userClient.userInfo(tenantId, username, userType);
if (!result.isSuccess()) {
return null;
}
// 构建oauth2用户信息
return TokenUtil.convertUser(result.getData(), request);
}
@Override
public OAuth2User loadByPhone(String phone, OAuth2Request request) {
// 获取用户参数
String userType = Optional.ofNullable(request.getUserType())
.filter(s -> !StringUtil.isBlank(s))
.orElse(UserType.WEB.getName());
String tenantId = request.getTenantId();
// 获取用户信息
R<UserInfo> result = userClient.userInfoByPhone(tenantId, phone, userType);
if (!result.isSuccess()) {
return null;
}
// 构建oauth2用户信息
return TokenUtil.convertUser(result.getData(), request);
}
@Override
public boolean validateUser(OAuth2User user) {
return Optional.ofNullable(user)
.filter(u -> u.getUserId() != null && !u.getUserId().isEmpty()) // 检查userId不为空
.filter(u -> u.getAuthorities() != null && !u.getAuthorities().isEmpty()) // 检查authorities不为空
.isPresent(); // 如果上述条件都满足则返回true否则返回false
}
}

View File

@ -0,0 +1,88 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.auth.utils;
import org.springblade.core.oauth2.provider.OAuth2Request;
import org.springblade.core.oauth2.service.OAuth2User;
import org.springblade.core.oauth2.service.impl.OAuth2UserDetail;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.SysCache;
import org.springblade.system.pojo.entity.User;
import org.springblade.system.pojo.entity.UserInfo;
import java.util.Collections;
/**
* 认证工具类
*
* @author Chill
*/
public class TokenUtil {
/**
* 系统用户转换为OAuth2标准用户
*
* @param userInfo 用户信息
* @param request 请求信息
* @return OAuth2User
*/
public static OAuth2User convertUser(UserInfo userInfo, OAuth2Request request) {
// 为空则返回null
if (userInfo == null || userInfo.getUser() == null) {
return null;
}
User user = userInfo.getUser();
String userDept = request.getUserDept();
String userRole = request.getUserRole();
// 单独指定部门
if (Func.isNotEmpty(userDept) && user.getDeptId().contains(userDept)) {
user.setDeptId(userDept);
}
// 单独指定角色
if (Func.isNotEmpty(userRole) && user.getRoleId().contains(userRole)) {
user.setRoleId(userRole);
userInfo.setRoles(SysCache.getRoleAliases(userRole));
}
// 构建oauth2所需用户信息
OAuth2UserDetail userDetail = new OAuth2UserDetail();
userDetail.setUserId(String.valueOf(user.getId()));
userDetail.setOauthId(userInfo.getOauthId());
userDetail.setTenantId(user.getTenantId());
userDetail.setName(user.getName());
userDetail.setRealName(user.getRealName());
userDetail.setAccount(user.getAccount());
userDetail.setPassword(user.getPassword());
userDetail.setDeptId(user.getDeptId());
userDetail.setPostId(user.getPostId());
userDetail.setRoleId(user.getRoleId());
userDetail.setRoleName(Func.join(userInfo.getRoles()));
userDetail.setAvatar(user.getAvatar());
userDetail.setAuthorities(userInfo.getRoles());
userDetail.setDetail(userInfo.getDetail());
return userDetail;
}
}

View File

@ -0,0 +1,15 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.dev.url}
username: ${blade.datasource.dev.username}
password: ${blade.datasource.dev.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:2888

View File

@ -0,0 +1,15 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.prod.url}
username: ${blade.datasource.prod.username}
password: ${blade.datasource.prod.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:2888

View File

@ -0,0 +1,15 @@
#服务器端口
server:
port: 8100
#数据源配置
spring:
datasource:
url: ${blade.datasource.test.url}
username: ${blade.datasource.test.username}
password: ${blade.datasource.test.password}
#第三方登陆
social:
enabled: true
domain: http://127.0.0.1:2888

View File

@ -0,0 +1,65 @@
# 在使用Spring默认数据源Hikari的情况下配置以下配置项
spring:
datasource:
hikari:
# 自动提交从池中返回的连接
auto-commit: true
# 连接池中维护的最小空闲连接数
minimum-idle: 10
# 连接池中允许的最大连接数。缺省值10推荐的公式((core_count * 2) + effective_spindle_count)
maximum-pool-size: 60
# 空闲连接超时时间默认值60000010分钟大于等于max-lifetime且max-lifetime>0会被重置为0不等于0且小于10秒会被重置为10秒。
# 只有空闲连接数大于最大连接数且空闲时间超过该值,才会被释放
idle-timeout: 30000
# 连接最大存活时间.不等于0且小于30秒会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
max-lifetime: 1800000
# 等待连接池分配连接的最大时长毫秒超过这个时长还没可用的连接则发生SQLException 缺省:30秒
connection-timeout: 30000
# 连接测试查询
connection-test-query: select 1
#connection-test-query: select 1 from dual
freemarker:
# 模板后缀名
suffix: .ftl
# 文档类型
content-type: text/html
# 页面编码
charset: UTF-8
# 页面缓存
cache: false
# 模板路径
template-loader-path: classpath:/templates/
web:
# 资源路径
resources:
static-locations: classpath:/static/
#swagger文档
swagger:
base-packages:
- org.springblade
- org.springframework.security.oauth2.provider.endpoint
#第三方登陆
social:
oauth:
GITHUB:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/github
GITEE:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/gitee
WECHAT_OPEN:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/wechat
QQ:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/qq
DINGTALK:
client-id: 233************
client-secret: 233************************************
redirect-uri: ${social.domain}/oauth/redirect/dingtalk

View File

@ -0,0 +1,47 @@
package org.springblade.test;
import org.springblade.core.tool.utils.AesUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.StringPool;
/**
* Key生成器
*
* @author Chill
*/
public class CryptoKeyGenerator {
public static void main(String[] args) {
String cryptoKey = AesUtil.genAesKey();
String aesKey = AesUtil.genAesKey();
String desKey = DesUtil.genDesKey();
System.out.println("=========== blade.token.crypto-key 配置如下 ============");
System.out.println("#blade配置\n" +
"blade:\n" +
" token:\n" +
" crypto-key: " + cryptoKey);
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== blade.api.crypto 配置如下 ===============");
System.out.println("#blade配置\n" +
"blade:\n" +
" api:\n" +
" crypto:\n" +
" enabled: true\n" +
" aes-key: " + aesKey + "\n" +
" des-key: " + desKey);
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== saber crypto.js 配置如下 ===============");
System.out.println("export default class crypto {\n" +
" static cryptoKey = '" + cryptoKey + "';\n" +
" static aesKey = '" + aesKey + "';\n" +
" static desKey = '" + desKey + "';\n" +
"}");
System.out.println("=======================================================");
}
}

View File

@ -0,0 +1,45 @@
package org.springblade.test;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.springblade.core.tool.utils.AesUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.SM4Util;
/**
* 加密密钥生成器
*
* @author BladeX
*/
public class EncryptKeyGenerator {
public static void main(String[] args) {
// 生成对称加密密钥
String aesKey = AesUtil.genAesKey();
String desKey = DesUtil.genDesKey();
String sm4Key = SM4Util.generateKey();
// 生成SM2非对称加密密钥对
AsymmetricCipherKeyPair sm2KeyPair = SM2Util.generateKeyPair();
String sm2PublicKey = SM2Util.getPublicKeyString(sm2KeyPair);
String sm2PrivateKey = SM2Util.getPrivateKeyString(sm2KeyPair);
System.out.println("\n================== Encryption Keys Generated ==================\n");
System.out.println("[Symmetric Keys / 对称加密密钥]");
System.out.println();
System.out.println("AES-256-Key: " + aesKey);
System.out.println("DES-Key: " + desKey);
System.out.println("SM4-Key(国密): " + sm4Key);
System.out.println("\n----------------------------------------------------------------\n");
System.out.println("[Asymmetric Keys / 非对称加密密钥]");
System.out.println();
System.out.println("SM2-PublicKey(国密公钥): " + sm2PublicKey);
System.out.println("SM2-PrivateKey(国密私钥): " + sm2PrivateKey);
System.out.println("\n================================================================\n");
}
}

View File

@ -0,0 +1,22 @@
package org.springblade.test;
import org.springblade.core.tool.utils.RandomType;
import org.springblade.core.tool.utils.StringUtil;
/**
* signKey生成器
*
* @author Chill
*/
public class SignKeyGenerator {
public static void main(String[] args) {
System.out.println("=========== blade.token.sign-key 配置如下 ==============");
System.out.println("#blade配置\n" +
"blade:\n" +
" token:\n" +
" sign-key: " + StringUtil.random(32, RandomType.ALL) );
System.out.println("=======================================================");
}
}

View File

@ -0,0 +1,46 @@
package org.springblade.test;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.util.encoders.Hex;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringPool;
/**
* 国密算法生成器
*
* @author Chill
*/
public class Sm2KeyGenerator {
public static void main(String[] args) {
System.out.println("================ blade.oauth2 配置如下 =================");
AsymmetricCipherKeyPair keyPair = SM2Util.generateKeyPair();
String publicKey = SM2Util.getPublicKeyString(keyPair);
String privateKey = SM2Util.getPrivateKeyString(keyPair);
System.out.println("#blade配置 \n" +
"blade:\n" +
" oauth2:\n" +
" enabled: true\n" +
" public-key: " + publicKey + "\n" +
" private-key: " + privateKey);
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== saber website.js 配置如下 ===============");
System.out.println("//saber配置\n" +
"oauth2: {\n" +
" publicKey: '" + publicKey + "',\n" +
"}");
System.out.println("=======================================================");
System.out.println(StringPool.EMPTY);
System.out.println("============== 密码:[admin] 加密流程如下 ================");
String password = "admin";
byte[] encryptedData = SM2Util.encrypt(password, publicKey);
String decryptedText = SM2Util.decrypt(encryptedData, privateKey);
System.out.println("加密前: " + password);
System.out.println("加密后: " + Hex.toHexString(encryptedData));
System.out.println("解密后: " + decryptedText);
System.out.println("请注意: 此密文为前端加密后调用token接口的密码参数");
System.out.println("=======================================================");
}
}

View File

@ -0,0 +1,120 @@
package org.springblade.test;
import lombok.SneakyThrows;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.util.encoders.Hex;
import org.springblade.core.tool.utils.SM2Util;
import org.springblade.core.tool.utils.StringUtil;
/**
* SM2Test
*
* @author Chill
*/
public class Sm2Test {
@SneakyThrows
public static void main(String[] args) {
System.out.println("================== SM2 加解密与签名测试 ==================");
// 1. 生成SM2密钥对
AsymmetricCipherKeyPair keyPair = SM2Util.generateKeyPair();
String publicKeyString = SM2Util.getPublicKeyString(keyPair);
String privateKeyString = SM2Util.getPrivateKeyString(keyPair);
System.out.println("1. 生成SM2密钥对:");
System.out.println(" 公钥 (16进制): " + publicKeyString);
System.out.println(" 公钥长度: " + publicKeyString.length());
System.out.println(" 私钥 (16进制): " + privateKeyString);
System.out.println(" 私钥长度: " + privateKeyString.length());
System.out.println("--------------------------------------------------");
// 2. 从字符串恢复密钥
System.out.println("2. 从字符串恢复密钥...");
ECPublicKeyParameters publicKey = SM2Util.stringToPublicKey(publicKeyString);
ECPrivateKeyParameters privateKey = SM2Util.stringToPrivateKey(privateKeyString);
System.out.println(" 密钥恢复成功!");
System.out.println("--------------------------------------------------");
// 3. 准备待加密的原文
String originalText = "Hello BladeX! 这是一段需要被国密SM2算法加密和签名的敏感信息。1234567890";
System.out.println("3. 待加密的原文: " + originalText);
System.out.println("--------------------------------------------------");
// 4. 执行加密
System.out.println("4. 正在执行加密操作...");
byte[] encryptedData = SM2Util.encrypt(originalText, publicKey);
if (encryptedData != null && encryptedData.length > 0) {
System.out.println(" 加密成功!");
System.out.println(" 加密后的密文 (16进制): " + Hex.toHexString(encryptedData));
System.out.println(" 密文长度: " + encryptedData.length + " 字节");
} else {
System.out.println(" 加密失败!");
return;
}
System.out.println("--------------------------------------------------");
// 5. 执行解密
System.out.println("5. 正在执行解密操作...");
String decryptedText = SM2Util.decrypt(encryptedData, privateKey);
if (StringUtil.isNotBlank(decryptedText)) {
System.out.println(" 解密成功!");
System.out.println(" 解密后的明文: " + decryptedText);
} else {
System.out.println(" 解密失败!");
return;
}
System.out.println("--------------------------------------------------");
// 6. 执行数字签名
System.out.println("6. 正在执行数字签名...");
byte[] signature = SM2Util.sign(originalText, privateKey);
if (signature != null && signature.length > 0) {
System.out.println(" 签名成功!");
System.out.println(" 数字签名 (16进制): " + Hex.toHexString(signature));
System.out.println(" 签名长度: " + signature.length + " 字节");
} else {
System.out.println(" 签名失败!");
return;
}
System.out.println("--------------------------------------------------");
// 7. 验证签名
System.out.println("7. 正在验证数字签名...");
boolean isVerified = SM2Util.verify(originalText, signature, publicKey);
System.out.println(" 签名验证结果: " + (isVerified ? "有效" : "无效"));
System.out.println("--------------------------------------------------");
// 8. 校验加解密结果
System.out.println("8. 正在校验原文与解密后的明文是否一致...");
boolean isDecryptMatch = originalText.equals(decryptedText);
System.out.println(" 加解密校验结果: " + (isDecryptMatch ? "一致" : "不一致"));
System.out.println("==================================================");
// 9. 最终结果汇总
if (isDecryptMatch && isVerified) {
System.out.println("\n[成功] SM2加解密与签名流程验证通过");
System.out.println(" ✓ 密钥对生成成功");
System.out.println(" ✓ 加解密功能正常");
System.out.println(" ✓ 数字签名验证通过");
} else {
System.out.println("\n[失败] SM2加解密与签名流程验证失败");
if (!isDecryptMatch) {
System.out.println(" ✗ 加解密校验失败");
}
if (!isVerified) {
System.out.println(" ✗ 数字签名验证失败");
}
}
}
}

View File

@ -0,0 +1,71 @@
package org.springblade.test;
import lombok.SneakyThrows;
import org.springblade.core.tool.utils.SM4Util;
import org.springblade.core.tool.utils.StringUtil;
/**
* Sm4Test
*
* @author BladeX
*/
public class Sm4Test {
@SneakyThrows
public static void main(String[] args) {
System.out.println("================== SM4 加解密测试 ==================");
// 1. 生成SM4密钥
String sm4Key = SM4Util.generateKey();
System.out.println("1. 生成SM4密钥 (16进制): " + sm4Key);
System.out.println(" 密钥长度 (Hex): " + sm4Key.length());
System.out.println("--------------------------------------------------");
// 2. 准备待加密的原文
String originalText = "Hello BladeX! 这是一段需要被国密SM4算法加密的敏感信息。1234567890";
System.out.println("2. 待加密的原文: " + originalText);
System.out.println("--------------------------------------------------");
// 3. 执行加密
System.out.println("3. 正在执行加密操作...");
String encryptedText = SM4Util.encrypt(originalText, sm4Key);
if (StringUtil.isNotBlank(encryptedText)) {
System.out.println(" 加密成功!");
System.out.println(" 加密后的密文 (16进制): " + encryptedText);
} else {
System.out.println(" 加密失败!");
return;
}
System.out.println("--------------------------------------------------");
// 4. 执行解密
System.out.println("4. 正在执行解密操作...");
String decryptedText = SM4Util.decrypt(encryptedText, sm4Key);
if (StringUtil.isNotBlank(decryptedText)) {
System.out.println(" 解密成功!");
System.out.println(" 解密后的明文: " + decryptedText);
} else {
System.out.println(" 解密失败!");
return;
}
System.out.println("--------------------------------------------------");
// 5. 校验结果
System.out.println("5. 正在校验原文与解密后的明文是否一致...");
boolean isMatch = originalText.equals(decryptedText);
System.out.println(" 校验结果: " + (isMatch ? "一致" : "不一致"));
System.out.println("==================================================");
if (isMatch) {
System.out.println("\n[成功] SM4加解密流程验证通过");
} else {
System.out.println("\n[失败] SM4加解密流程验证失败");
}
}
}

45
blade-common/pom.xml Normal file
View File

@ -0,0 +1,45 @@
<?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">
<parent>
<artifactId>BladeX</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-common</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
<finalName>${project.name}</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,63 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.cache;
/**
* 缓存名
*
* @author Chill
*/
public interface CacheNames {
/**
* 返回拼接后的key
*
* @param cacheKey 缓存key
* @param cacheKeyValue 缓存key值
* @return tenantKey
*/
static String cacheKey(String cacheKey, String cacheKeyValue) {
return cacheKey.concat(cacheKeyValue);
}
/**
* 返回租户格式的key
*
* @param tenantId 租户编号
* @param cacheKey 缓存key
* @param cacheKeyValue 缓存key值
* @return tenantKey
*/
static String tenantKey(String tenantId, String cacheKey, String cacheKeyValue) {
return tenantId.concat(":").concat(cacheKey).concat(cacheKeyValue);
}
/**
* 验证码key
*/
String CAPTCHA_KEY = "blade:auth::blade:captcha:";
}

View File

@ -0,0 +1,41 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.config;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
/**
* 公共封装包配置类
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@AllArgsConstructor
public class BladeCommonConfiguration {
}

View File

@ -0,0 +1,75 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.constant;
/**
* 通用常量
*
* @author Chill
*/
public interface CommonConstant {
/**
* sword 系统名
*/
String SWORD_NAME = "sword";
/**
* saber 系统名
*/
String SABER_NAME = "saber";
/**
* 顶级父节点id
*/
Long TOP_PARENT_ID = 0L;
/**
* 顶级父节点名称
*/
String TOP_PARENT_NAME = "顶级";
/**
* 未封存状态值
*/
Integer NOT_SEALED_ID = 0;
/**
* 默认排序字段
*/
String SORT_FIELD = "sort";
/**
* 数据权限类型
*/
Integer DATA_SCOPE_CATEGORY = 1;
/**
* 接口权限类型
*/
Integer API_SCOPE_CATEGORY = 2;
}

View File

@ -0,0 +1,222 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.constant;
import org.springblade.core.launch.constant.AppConstant;
/**
* 启动常量
*
* @author Chill
*/
public interface LauncherConstant {
/**
* nacos 用户名
*/
String NACOS_USERNAME = "nacos";
/**
* nacos 密码
*/
String NACOS_PASSWORD = "nacos";
/**
* nacos dev 地址
*/
String NACOS_DEV_ADDR = "127.0.0.1:8848";
/**
* nacos prod 地址
*/
String NACOS_PROD_ADDR = "172.30.0.48:8848";
/**
* nacos test 地址
*/
String NACOS_TEST_ADDR = "nacos-nodeport.procure.svc.cluster.local:8848";
/**
* sentinel dev 地址
*/
String SENTINEL_DEV_ADDR = "127.0.0.1:8858";
/**
* sentinel prod 地址
*/
String SENTINEL_PROD_ADDR = "172.30.0.58:8858";
/**
* sentinel test 地址
*/
String SENTINEL_TEST_ADDR = "172.30.0.58:8858";
/**
* seata dev 地址
*/
String SEATA_DEV_ADDR = "127.0.0.1:8091";
/**
* seata prod 地址
*/
String SEATA_PROD_ADDR = "172.30.0.68:8091";
/**
* seata test 地址
*/
String SEATA_TEST_ADDR = "172.30.0.68:8091";
/**
* zipkin dev 地址
*/
String ZIPKIN_DEV_ADDR = "http://127.0.0.1:9411";
/**
* zipkin prod 地址
*/
String ZIPKIN_PROD_ADDR = "http://172.30.0.71:9411";
/**
* zipkin test 地址
*/
String ZIPKIN_TEST_ADDR = "http://172.30.0.71:9411";
/**
* elk dev 地址
*/
String ELK_DEV_ADDR = "127.0.0.1:9000";
/**
* elk prod 地址
*/
String ELK_PROD_ADDR = "172.30.0.72:9000";
/**
* elk test 地址
*/
String ELK_TEST_ADDR = "172.30.0.72:9000";
/**
* seata file模式
*/
String FILE_MODE = "file";
/**
* seata nacos模式
*/
String NACOS_MODE = "nacos";
/**
* seata default模式
*/
String DEFAULT_MODE = "default";
/**
* seata group后缀
*/
String GROUP_NAME = "-group";
/**
* seata 服务组格式
*
* @param appName 服务名
* @return group
*/
static String seataServiceGroup(String appName) {
return appName.concat(GROUP_NAME);
}
/**
* 动态获取nacos地址
*
* @param profile 环境变量
* @return addr
*/
static String nacosAddr(String profile) {
return switch (profile) {
case (AppConstant.PROD_CODE) -> NACOS_PROD_ADDR;
case (AppConstant.TEST_CODE) -> NACOS_TEST_ADDR;
default -> NACOS_DEV_ADDR;
};
}
/**
* 动态获取sentinel地址
*
* @param profile 环境变量
* @return addr
*/
static String sentinelAddr(String profile) {
return switch (profile) {
case (AppConstant.PROD_CODE) -> SENTINEL_PROD_ADDR;
case (AppConstant.TEST_CODE) -> SENTINEL_TEST_ADDR;
default -> SENTINEL_DEV_ADDR;
};
}
/**
* 动态获取seata地址
*
* @param profile 环境变量
* @return addr
*/
static String seataAddr(String profile) {
return switch (profile) {
case (AppConstant.PROD_CODE) -> SEATA_PROD_ADDR;
case (AppConstant.TEST_CODE) -> SEATA_TEST_ADDR;
default -> SEATA_DEV_ADDR;
};
}
/**
* 动态获取zipkin地址
*
* @param profile 环境变量
* @return addr
*/
static String zipkinAddr(String profile) {
return switch (profile) {
case (AppConstant.PROD_CODE) -> ZIPKIN_PROD_ADDR;
case (AppConstant.TEST_CODE) -> ZIPKIN_TEST_ADDR;
default -> ZIPKIN_DEV_ADDR;
};
}
/**
* 动态获取elk地址
*
* @param profile 环境变量
* @return addr
*/
static String elkAddr(String profile) {
return switch (profile) {
case (AppConstant.PROD_CODE) -> ELK_PROD_ADDR;
case (AppConstant.TEST_CODE) -> ELK_TEST_ADDR;
default -> ELK_DEV_ADDR;
};
}
}

View File

@ -0,0 +1,99 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.constant;
import java.util.Arrays;
import java.util.List;
/**
* 系统参数常量
* 统一管理所有通过 ParamCache 读取的参数key及其默认值
*
* @author BladeX
*/
public interface ParamConstant {
// ==================== 账号相关 ====================
/**
* 是否开启注册参数key
*/
String REGISTER_USER_VALUE = "account.registerUser";
/**
* 账号默认密码参数key
*/
String DEFAULT_PARAM_PASSWORD = "account.initPassword";
/**
* 账号默认密码
*/
String DEFAULT_PASSWORD = "123456";
/**
* 账号锁定错误次数参数key
*/
String FAIL_COUNT_VALUE = "account.failCount";
/**
* 账号锁定默认错误次数
*/
Integer FAIL_COUNT = 5;
/**
* 账号锁定时长参数key单位分钟
*/
String LOCK_DURATION_VALUE = "account.lockDuration";
/**
* 账号锁定默认时长单位分钟
*/
Integer LOCK_DURATION = 30;
// ==================== 租户相关 ====================
/**
* 租户默认密码参数key
*/
String TENANT_PASSWORD_KEY = "tenant.default.password";
/**
* 租户默认密码
*/
String TENANT_DEFAULT_PASSWORD = "123456";
/**
* 租户默认账号额度参数key
*/
String TENANT_ACCOUNT_NUMBER_KEY = "tenant.default.accountNumber";
/**
* 租户默认账号额度
*/
Integer TENANT_DEFAULT_ACCOUNT_NUMBER = -1;
/**
* 租户默认菜单集合参数key
*/
String TENANT_MENU_CODE_KEY = "tenant.default.menuCode";
/**
* 租户默认菜单集合
*/
List<String> TENANT_MENU_CODES = Arrays.asList(
"desk", "flow", "work", "monitor", "resource", "role", "user", "dept", "dictbiz", "topmenu"
);
}

View File

@ -0,0 +1,40 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.constant;
/**
* 租户常量
*
* @author Chill
*/
public interface TenantConstant {
/**
* 租户授权码默认16位密钥
*/
String DES_KEY = "0000000000000000";
}

View File

@ -0,0 +1,77 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.launch;
import org.springblade.common.constant.LauncherConstant;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.service.LauncherService;
import org.springblade.core.launch.utils.PropsUtil;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
/**
* 启动参数拓展
*
* @author smallchil
*/
@AutoService(LauncherService.class)
public class LauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
Properties props = System.getProperties();
// nacos注册中心配置
PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.username", LauncherConstant.NACOS_USERNAME);
PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.password", LauncherConstant.NACOS_PASSWORD);
PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", LauncherConstant.nacosAddr(profile));
// nacos配置中心配置
PropsUtil.setProperty(props, "spring.cloud.nacos.config.username", LauncherConstant.NACOS_USERNAME);
PropsUtil.setProperty(props, "spring.cloud.nacos.config.password", LauncherConstant.NACOS_PASSWORD);
PropsUtil.setProperty(props, "spring.cloud.nacos.config.server-addr", LauncherConstant.nacosAddr(profile));
// sentinel配置
PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
// 多数据源配置
PropsUtil.setProperty(props, "spring.datasource.dynamic.enabled", "false");
// 开启elk日志
// PropsUtil.setProperty(props, "blade.log.elk.destination", LauncherConstant.elkAddr(profile));
// seata注册地址
// PropsUtil.setProperty(props, "seata.service.grouplist.default", LauncherConstant.seataAddr(profile));
// seata注册group格式
// PropsUtil.setProperty(props, "seata.tx-service-group", LauncherConstant.seataServiceGroup(appName));
// seata配置服务group
// PropsUtil.setProperty(props, "seata.service.vgroup-mapping.".concat(LauncherConstant.seataServiceGroup(appName)), LauncherConstant.DEFAULT_MODE);
// seata注册模式配置
// PropsUtil.setProperty(props, "seata.registry.type", LauncherConstant.NACOS_MODE);
// PropsUtil.setProperty(props, "seata.registry.nacos.server-addr", LauncherConstant.nacosAddr(profile));
// PropsUtil.setProperty(props, "seata.config.type", LauncherConstant.NACOS_MODE);
// PropsUtil.setProperty(props, "seata.config.nacos.server-addr", LauncherConstant.nacosAddr(profile));
}
}

View File

@ -0,0 +1,35 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.common.utils;
/**
* 通用工具类
*
* @author Chill
*/
public class CommonUtil {
}

View File

@ -0,0 +1,8 @@
${AnsiColor.BLUE} ______ _ _ ___ ___
${AnsiColor.BLUE} | ___ \| | | | \ \ / /
${AnsiColor.BLUE} | |_/ /| | __ _ __| | ___ \ V /
${AnsiColor.BLUE} | ___ \| | / _` | / _` | / _ \ > <
${AnsiColor.BLUE} | |_/ /| || (_| || (_| || __/ / . \
${AnsiColor.BLUE} \____/ |_| \__,_| \__,_| \___|/__/ \__\
${AnsiColor.BLUE}:: BladeX ${blade.service.version} :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}

View File

@ -0,0 +1,24 @@
# 验证错误
error.validation.default=参数校验失败。
user.name.required=请输入姓名。
user.name.size=姓名长度需在{min}到{max}个字符之间。
user.email.invalid=请输入有效的邮箱地址。
user.description.size=描述不能超过{max}个字符。
# 业务错误
error.biz.denied=不允许的操作:{0}。
error.auth.unauthorized=请先登录。
error.permission.denied=您没有访问{0}的权限。
error.resource.notfound={0} ID {1} 不存在。
error.user.delete.admin=不能删除管理员用户。
error.unknown=未知错误类型:{0}
# 服务器错误
error.server.internal=服务器内部错误,请稍后重试。
error.server.busy=服务器繁忙,请稍后重试。
error.server.maintenance=系统维护中。
# 数据错误
error.data.duplicate=数据已存在。
error.data.invalid=数据格式无效。
error.data.notfound=数据不存在。

View File

@ -0,0 +1,24 @@
# Validierungsfehler
error.validation.default=Parametervalidierung fehlgeschlagen.
user.name.required=Bitte geben Sie einen Namen ein.
user.name.size=Der Name muss zwischen {min} und {max} Zeichen lang sein.
user.email.invalid=Bitte geben Sie eine gültige E-Mail-Adresse ein.
user.description.size=Die Beschreibung darf {max} Zeichen nicht überschreiten.
# Geschäftsfehler
error.biz.denied=Operation nicht erlaubt: {0}.
error.auth.unauthorized=Bitte melden Sie sich zuerst an.
error.permission.denied=Sie haben keine Berechtigung für den Zugriff auf {0}.
error.resource.notfound={0} mit ID {1} existiert nicht.
error.user.delete.admin=Administrator-Benutzer kann nicht gelöscht werden.
error.unknown=Unbekannter Fehlertyp: {0}
# Serverfehler
error.server.internal=Interner Serverfehler. Bitte versuchen Sie es später erneut.
error.server.busy=Server ist ausgelastet. Bitte versuchen Sie es später erneut.
error.server.maintenance=System wird gewartet.
# Datenfehler
error.data.duplicate=Daten existieren bereits.
error.data.invalid=Ungültiges Datenformat.
error.data.notfound=Daten nicht gefunden.

View File

@ -0,0 +1,24 @@
# Validation Errors
error.validation.default=Parameter validation failed.
user.name.required=Please enter a name.
user.name.size=Name must be between {min} and {max} characters.
user.email.invalid=Please enter a valid email address.
user.description.size=Description cannot exceed {max} characters.
# Business Errors
error.biz.denied=Operation not permitted: {0}.
error.auth.unauthorized=Please log in first.
error.permission.denied=You do not have permission to access {0}.
error.resource.notfound={0} with ID {1} does not exist.
error.user.delete.admin=Cannot delete administrator user.
error.unknown=Unknown error type: {0}
# Server Errors
error.server.internal=Internal server error. Please try again later.
error.server.busy=Server is busy. Please try again later.
error.server.maintenance=System is under maintenance.
# Data Errors
error.data.duplicate=Data already exists.
error.data.invalid=Invalid data format.
error.data.notfound=Data not found.

View File

@ -0,0 +1,24 @@
# Validation errors
error.validation.default=Validation failed.
user.name.required=Name is required.
user.name.size=Name length must be between {min} and {max} characters.
user.email.invalid=Please provide a valid email address.
user.description.size=Description cannot exceed {max} characters.
# Business errors
error.biz.denied=Operation {0} is not allowed.
error.auth.unauthorized=Authentication required.
error.permission.denied=You don't have permission to access {0}.
error.resource.notfound={0} with ID {1} not found.
error.user.delete.admin=Cannot delete admin user.
error.unknown=Unknown error type: {0}
# Server errors
error.server.internal=Internal server error. Please try again later.
error.server.busy=Server is busy. Please try again later.
error.server.maintenance=System is under maintenance.
# Data errors
error.data.duplicate=Duplicate data found.
error.data.invalid=Invalid data format.
error.data.notfound=Data not found.

View File

@ -0,0 +1,24 @@
# Erreurs de validation
error.validation.default=Échec de la validation des paramètres.
user.name.required=Veuillez saisir un nom.
user.name.size=Le nom doit contenir entre {min} et {max} caractères.
user.email.invalid=Veuillez saisir une adresse e-mail valide.
user.description.size=La description ne peut pas dépasser {max} caractères.
# Erreurs métier
error.biz.denied=Opération non autorisée : {0}.
error.auth.unauthorized=Veuillez vous connecter d'abord.
error.permission.denied=Vous n'avez pas l'autorisation d'accéder à {0}.
error.resource.notfound={0} avec l'ID {1} n'existe pas.
error.user.delete.admin=Impossible de supprimer l'utilisateur administrateur.
error.unknown=Type d'erreur inconnu : {0}
# Erreurs serveur
error.server.internal=Erreur interne du serveur. Veuillez réessayer plus tard.
error.server.busy=Le serveur est occupé. Veuillez réessayer plus tard.
error.server.maintenance=Système en maintenance.
# Erreurs de données
error.data.duplicate=Les données existent déjà.
error.data.invalid=Format de données invalide.
error.data.notfound=Données introuvables.

View File

@ -0,0 +1,24 @@
# Errori di validazione
error.validation.default=Validazione dei parametri fallita.
user.name.required=Inserisci il nome.
user.name.size=La lunghezza del nome deve essere tra {min} e {max} caratteri.
user.email.invalid=Inserisci un indirizzo email valido.
user.description.size=La descrizione non può superare {max} caratteri.
# Errori di business
error.biz.denied=Operazione non consentita: {0}.
error.auth.unauthorized=Effettua il login prima di procedere.
error.permission.denied=Non hai i permessi per accedere a {0}.
error.resource.notfound={0} con ID {1} non esiste.
error.user.delete.admin=Non è possibile eliminare l'utente amministratore.
error.unknown=Tipo di errore sconosciuto: {0}
# Errori del server
error.server.internal=Errore interno del server, riprova più tardi.
error.server.busy=Il server è occupato, riprova più tardi.
error.server.maintenance=Sistema in manutenzione.
# Errori di dati
error.data.duplicate=I dati esistono già.
error.data.invalid=Formato dati non valido.
error.data.notfound=I dati non esistono.

View File

@ -0,0 +1,24 @@
# Ошибки валидации
error.validation.default=Ошибка проверки параметров.
user.name.required=Пожалуйста, введите имя.
user.name.size=Имя должно быть от {min} до {max} символов.
user.email.invalid=Пожалуйста, введите действительный адрес электронной почты.
user.description.size=Описание не может превышать {max} символов.
# Бизнес-ошибки
error.biz.denied=Операция не разрешена: {0}.
error.auth.unauthorized=Пожалуйста, сначала войдите в систему.
error.permission.denied=У вас нет разрешения на доступ к {0}.
error.resource.notfound={0} с ID {1} не существует.
error.user.delete.admin=Невозможно удалить пользователя-администратора.
error.unknown=Неизвестный тип ошибки: {0}
# Ошибки сервера
error.server.internal=Внутренняя ошибка сервера. Пожалуйста, попробуйте позже.
error.server.busy=Сервер занят. Пожалуйста, попробуйте позже.
error.server.maintenance=Система на обслуживании.
# Ошибки данных
error.data.duplicate=Данные уже существуют.
error.data.invalid=Недопустимый формат данных.
error.data.notfound=Данные не найдены.

View File

@ -0,0 +1,24 @@
# 验证错误
error.validation.default=参数校验失败。
user.name.required=请输入姓名。
user.name.size=姓名长度需在{min}到{max}个字符之间。
user.email.invalid=请输入有效的邮箱地址。
user.description.size=描述不能超过{max}个字符。
# 业务错误
error.biz.denied=不允许的操作:{0}。
error.auth.unauthorized=请先登录。
error.permission.denied=您没有访问{0}的权限。
error.resource.notfound={0} ID {1} 不存在。
error.user.delete.admin=不能删除管理员用户。
error.unknown=未知错误类型:{0}
# 服务器错误
error.server.internal=服务器内部错误,请稍后重试。
error.server.busy=服务器繁忙,请稍后重试。
error.server.maintenance=系统维护中。
# 数据错误
error.data.duplicate=数据已存在。
error.data.invalid=数据格式无效。
error.data.notfound=数据不存在。

View File

@ -0,0 +1,24 @@
# 驗證錯誤
error.validation.default=參數校驗失敗。
user.name.required=請輸入姓名。
user.name.size=姓名長度需在{min}到{max}個字元之間。
user.email.invalid=請輸入有效的電子郵件地址。
user.description.size=描述不能超過{max}個字元。
# 業務錯誤
error.biz.denied=不允許的操作:{0}。
error.auth.unauthorized=請先登入。
error.permission.denied=您沒有存取{0}的權限。
error.resource.notfound={0} ID {1} 不存在。
error.user.delete.admin=不能刪除管理員使用者。
error.unknown=未知錯誤類型:{0}
# 伺服器錯誤
error.server.internal=伺服器內部錯誤,請稍後重試。
error.server.busy=伺服器忙碌中,請稍後重試。
error.server.maintenance=系統維護中。
# 資料錯誤
error.data.duplicate=資料已存在。
error.data.invalid=資料格式無效。
error.data.notfound=資料不存在。

View File

@ -0,0 +1,14 @@
# 问候消息
greeting.message=你好,{0}
greeting.welcome=欢迎使用我们的应用
# 用户消息
user.create.success=用户 {0} 创建成功。
user.update.success=ID为 {1} 的用户 {0} 更新成功。
user.delete.success=ID为 {0} 的用户删除成功。
user.notfound=用户未找到
# 成功消息
operation.success=操作成功完成
save.success=数据保存成功
delete.success=数据删除成功

View File

@ -0,0 +1,14 @@
# Begrüßungsnachrichten
greeting.message=Hallo, {0}!
greeting.welcome=Willkommen in unserer Anwendung
# Benutzernachrichten
user.create.success=Benutzer {0} wurde erfolgreich erstellt.
user.update.success=Benutzer {0} mit ID {1} wurde erfolgreich aktualisiert.
user.delete.success=Benutzer mit ID {0} wurde erfolgreich gelöscht.
user.notfound=Benutzer nicht gefunden
# Erfolgsmeldungen
operation.success=Vorgang erfolgreich abgeschlossen
save.success=Daten erfolgreich gespeichert
delete.success=Daten erfolgreich gelöscht

View File

@ -0,0 +1,14 @@
# Greeting Messages
greeting.message=Hello, {0}!
greeting.welcome=Welcome to our application
# User Messages
user.create.success=User {0} has been successfully created.
user.update.success=User {0} with ID {1} has been successfully updated.
user.delete.success=User with ID {0} has been successfully deleted.
user.notfound=User not found
# Success Messages
operation.success=Operation completed successfully
save.success=Data saved successfully
delete.success=Data deleted successfully

View File

@ -0,0 +1,14 @@
# Greeting messages
greeting.message=Hello, {0}!
greeting.welcome=Welcome to our application
# User messages
user.create.success=User {0} created successfully.
user.update.success=User {0} with ID {1} updated successfully.
user.delete.success=User with ID {0} deleted successfully.
user.notfound=User not found
# Success messages
operation.success=Operation completed successfully
save.success=Data saved successfully
delete.success=Data deleted successfully

View File

@ -0,0 +1,14 @@
# Messages de salutation
greeting.message=Bonjour, {0} !
greeting.welcome=Bienvenue dans notre application
# Messages utilisateur
user.create.success=L'utilisateur {0} a été créé avec succès.
user.update.success=L'utilisateur {0} avec l'ID {1} a été mis à jour avec succès.
user.delete.success=L'utilisateur avec l'ID {0} a été supprimé avec succès.
user.notfound=Utilisateur introuvable
# Messages de succès
operation.success=Opération terminée avec succès
save.success=Données enregistrées avec succès
delete.success=Données supprimées avec succès

View File

@ -0,0 +1,14 @@
# Messaggi di saluto
greeting.message=Ciao, {0}!
greeting.welcome=Benvenuto nella nostra applicazione
# Messaggi utente
user.create.success=L'utente {0} è stato creato con successo.
user.update.success=L'utente {0} con ID {1} è stato aggiornato con successo.
user.delete.success=L'utente con ID {0} è stato eliminato con successo.
user.notfound=Utente non trovato
# Messaggi di successo
operation.success=Operazione completata con successo
save.success=Dati salvati con successo
delete.success=Dati eliminati con successo

View File

@ -0,0 +1,14 @@
# Приветственные сообщения
greeting.message=Здравствуйте, {0}!
greeting.welcome=Добро пожаловать в наше приложение
# Сообщения пользователя
user.create.success=Пользователь {0} успешно создан.
user.update.success=Пользователь {0} с ID {1} успешно обновлен.
user.delete.success=Пользователь с ID {0} успешно удален.
user.notfound=Пользователь не найден
# Сообщения об успехе
operation.success=Операция успешно завершена
save.success=Данные успешно сохранены
delete.success=Данные успешно удалены

View File

@ -0,0 +1,14 @@
# 问候消息
greeting.message=你好,{0}
greeting.welcome=欢迎使用我们的应用
# 用户消息
user.create.success=用户 {0} 创建成功。
user.update.success=ID为 {1} 的用户 {0} 更新成功。
user.delete.success=ID为 {0} 的用户删除成功。
user.notfound=用户未找到
# 成功消息
operation.success=操作成功完成
save.success=数据保存成功
delete.success=数据删除成功

View File

@ -0,0 +1,14 @@
# 問候訊息
greeting.message=你好,{0}
greeting.welcome=歡迎使用我們的應用
# 使用者訊息
user.create.success=使用者 {0} 建立成功。
user.update.success=ID為 {1} 的使用者 {0} 更新成功。
user.delete.success=ID為 {0} 的使用者刪除成功。
user.notfound=使用者未找到
# 成功訊息
operation.success=操作成功完成
save.success=資料儲存成功
delete.success=資料刪除成功

View File

@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>BladeX-Biz</artifactId> <artifactId>BladeX</artifactId>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<version>${revision}</version> <version>${revision}</version>
</parent> </parent>
@ -31,7 +31,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>
<artifactId>blade-biz-common</artifactId> <artifactId>blade-common</artifactId>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.springblade</groupId> <groupId>org.springblade</groupId>

View File

@ -3,32 +3,16 @@ server:
spring: spring:
cloud: cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: public
group: DEFAULT_GROUP
username: nacos
password: nacos
discovery:
server-addr: 127.0.0.1:8848
namespace:
group: DEFAULT_GROUP
username: nacos
password: nacos
gateway: gateway:
discovery: server:
locator: webflux:
enabled: true discovery:
locator:
enabled: true
loadbalancer: loadbalancer:
retry: retry:
enabled: true enabled: true
# 本地兜底JWT token 签名密钥
blade:
token:
sign-key: 8rnuOcKSlxfe1TcwXVzw8x4VQtB3PG08
# 兼容性说明新版gateway配置需要最后启动才能发现服务否则会出现404的问题 # 兼容性说明新版gateway配置需要最后启动才能发现服务否则会出现404的问题
# 此问题可等spring官方修复或临时处理方案采用下方旧版配置即可自动发现服务 # 此问题可等spring官方修复或临时处理方案采用下方旧版配置即可自动发现服务
#spring: #spring:

View File

@ -0,0 +1,16 @@
<?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">
<parent>
<artifactId>blade-ops-api</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-develop-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
</project>

View File

@ -0,0 +1,68 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.feign;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.tool.api.R;
import org.springblade.develop.pojo.entity.Datasource;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* IDatasourceClient
*
* @author Chill
*/
@FeignClient(
value = AppConstant.APPLICATION_DEVELOP_NAME,
fallback = IDatasourceClientFallback.class
)
public interface IDatasourceClient {
String API_PREFIX = "/feign/client/datasource";
String GET_DETAIL = API_PREFIX + "/detail";
String GET_LIST = API_PREFIX + "/list";
/**
* 获取数据源详情
*
* @param id 数据源ID
* @return R
*/
@GetMapping(GET_DETAIL)
R<Datasource> detail(@RequestParam("id") Long id);
/**
* 获取所有数据源列表
*
* @return R
*/
@GetMapping(GET_LIST)
R<List<Datasource>> list();
}

View File

@ -0,0 +1,52 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.feign;
import org.springblade.core.tool.api.R;
import org.springblade.develop.pojo.entity.Datasource;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 数据源远程调用失败处理类
*
* @author Chill
*/
@Component
public class IDatasourceClientFallback implements IDatasourceClient {
@Override
public R<Datasource> detail(Long id) {
return R.fail("远程调用失败");
}
@Override
public R<List<Datasource>> list() {
return R.fail("远程调用失败");
}
}

View File

@ -0,0 +1,153 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 代码生成DTO
*
* @author Chill
*/
@Data
public class GeneratorDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 上级菜单主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "上级菜单主键")
private Long menuId;
/**
* 数据源主键
*/
@Schema(description = "数据源主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long datasourceId;
/**
* 模型编号
*/
@Schema(description = "模型编号")
private String modelCode;
/**
* 物理表名
*/
@Schema(description = "物理表名")
private String modelTable;
/**
* 表单设计
*/
@Schema(description = "表单设计")
private String modelForm;
/**
* 模型类名
*/
@Schema(description = "模型类名")
private String modelClass;
/**
* 模块名称
*/
@Schema(description = "服务名称")
private String serviceName;
/**
* 模块名称
*/
@Schema(description = "模块名称")
private String codeName;
/**
* 表名
*/
@Schema(description = "表名")
private String tableName;
/**
* 实体名
*/
@Schema(description = "表前缀")
private String tablePrefix;
/**
* 主键名
*/
@Schema(description = "主键名")
private String pkName;
/**
* 后端包名
*/
@Schema(description = "后端包名")
private String packageName;
/**
* 基础业务模式
*/
@Schema(description = "基础业务模式")
private Integer baseMode;
/**
* 包装器模式
*/
@Schema(description = "包装器模式")
private Integer wrapMode;
/**
* 远程调用模式
*/
@Schema(description = "远程调用模式")
private Integer feignMode;
/**
* 代码风格
*/
@Schema(description = "代码风格")
private String codeStyle;
/**
* 后端路径
*/
@Schema(description = "后端路径")
private String apiPath;
/**
* 前端路径
*/
@Schema(description = "前端路径")
private String webPath;
}

View File

@ -0,0 +1,53 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.develop.pojo.entity.Model;
import org.springblade.develop.pojo.entity.ModelPrototype;
import java.io.Serial;
import java.util.List;
/**
* 代码模型DTO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class ModelDTO extends Model {
@Serial
private static final long serialVersionUID = 1L;
/**
* 代码建模原型
*/
private List<ModelPrototype> prototypes;
}

View File

@ -0,0 +1,197 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("blade_code")
@Schema(description = "Code对象")
public class Code implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 数据模型主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "数据模型主键")
private Long modelId;
/**
* 上级菜单主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "上级菜单主键")
private Long menuId;
/**
* 模块名称
*/
@Schema(description = "服务名称")
private String serviceName;
/**
* 模块名称
*/
@Schema(description = "模块名称")
private String codeName;
/**
* 表名
*/
@Schema(description = "表名")
private String tableName;
/**
* 实体名
*/
@Schema(description = "表前缀")
private String tablePrefix;
/**
* 主键名
*/
@Schema(description = "主键名")
private String pkName;
/**
* 后端包名
*/
@Schema(description = "后端包名")
private String packageName;
/**
* 模版类型
*/
@Schema(description = "模版类型")
private String templateType;
/**
* 作者信息
*/
@Schema(description = "作者信息")
private String author;
/**
* 子表模型主键
*/
@Schema(description = "子表模型主键")
private String subModelId;
/**
* 子表绑定外键
*/
@Schema(description = "子表绑定外键")
private String subFkId;
/**
* 树主键字段
*/
@Schema(description = "树主键字段")
private String treeId;
/**
* 树父主键字段
*/
@Schema(description = "树父主键字段")
private String treePid;
/**
* 树名称字段
*/
@Schema(description = "树名称字段")
private String treeName;
/**
* 基础业务模式
*/
@Schema(description = "基础业务模式")
private Integer baseMode;
/**
* 包装器模式
*/
@Schema(description = "包装器模式")
private Integer wrapMode;
/**
* 远程调用模式
*/
@Schema(description = "远程调用模式")
private Integer feignMode;
/**
* 代码风格
*/
@Schema(description = "代码风格")
private String codeStyle;
/**
* 后端路径
*/
@Schema(description = "后端路径")
private String apiPath;
/**
* 前端路径
*/
@Schema(description = "前端路径")
private String webPath;
/**
* 是否已删除
*/
@TableLogic
@Schema(description = "是否已删除")
private Integer isDeleted;
}

View File

@ -0,0 +1,92 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 代码生成器配置表 实体类
*
* @author BladeX
*/
@Data
@TableName("blade_code_setting")
@Schema(description = "CodeSetting对象")
public class CodeSetting implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@JsonSerialize(using = ToStringSerializer.class)
@Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 编号
*/
@Schema(description = "编号")
private String code;
/**
* 分类[1:默认配置 2:表单设计]
*/
@Schema(description = "业务状态", hidden = true)
private Integer category;
/**
* 配置项
*/
@Schema(description = "配置项")
private String settings;
/**
* 状态[1:正常]
*/
@Schema(description = "业务状态", hidden = true)
private Integer status;
/**
* 是否已删除
*/
@Schema(description = "是否已删除")
private Integer isDeleted;
}

View File

@ -0,0 +1,92 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据源配置表实体类
*
* @author Chill
*/
@Data
@TableName("blade_datasource")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据源配置表")
public class Datasource extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 数据源类型
*/
@Schema(description = "数据源类型")
private Integer category;
/**
* 名称
*/
@Schema(description = "名称")
private String name;
/**
* 驱动类
*/
@Schema(description = "驱动类")
private String driverClass;
/**
* 连接地址
*/
@Schema(description = "连接地址")
private String url;
/**
* 用户名
*/
@Schema(description = "用户名")
private String username;
/**
* 密码
*/
@Schema(description = "密码")
private String password;
/**
* 分库分表配置
*/
@Schema(description = "分库分表配置")
private String shardingConfig;
/**
* 备注
*/
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,85 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据模型表实体类
*
* @author Chill
*/
@Data
@TableName("blade_model")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据模型表")
public class Model extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 数据源主键
*/
@Schema(description = "数据源主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long datasourceId;
/**
* 模型名称
*/
@Schema(description = "模型名称")
private String modelName;
/**
* 模型编号
*/
@Schema(description = "模型编号")
private String modelCode;
/**
* 物理表名
*/
@Schema(description = "物理表名")
private String modelTable;
/**
* 模型类名
*/
@Schema(description = "模型类名")
private String modelClass;
/**
* 模型备注
*/
@Schema(description = "模型备注")
private String modelRemark;
}

View File

@ -0,0 +1,130 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.develop.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
import java.io.Serial;
/**
* 数据原型表实体类
*
* @author Chill
*/
@Data
@TableName("blade_model_prototype")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "数据原型表")
public class ModelPrototype extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 模型主键
*/
@Schema(description = "模型主键")
@JsonSerialize(using = ToStringSerializer.class)
private Long modelId;
/**
* 物理列名
*/
@Schema(description = "物理列名")
private String jdbcName;
/**
* 物理类型
*/
@Schema(description = "物理类型")
private String jdbcType;
/**
* 注释说明
*/
@Schema(description = "注释说明")
private String jdbcComment;
/**
* 实体列名
*/
@Schema(description = "实体列名")
private String propertyName;
/**
* 实体类型
*/
@Schema(description = "实体类型")
private String propertyType;
/**
* 实体类型引用
*/
@Schema(description = "实体类型引用")
private String propertyEntity;
/**
* 列表显示
*/
@Schema(description = "列表显示")
private Integer isList;
/**
* 表单显示
*/
@Schema(description = "表单显示")
private Integer isForm;
/**
* 独占一行
*/
@Schema(description = "独占一行")
private Integer isRow;
/**
* 组件类型
*/
@Schema(description = "组件类型")
private String componentType;
/**
* 字典编码
*/
@Schema(description = "字典编码")
private String dictCode;
/**
* 是否必填
*/
@Schema(description = "是否必填")
private Integer isRequired;
/**
* 查询配置
*/
@Schema(description = "查询配置")
private Integer isQuery;
/**
* 查询类型
*/
@Schema(description = "查询类型")
private String queryType;
}

View File

@ -0,0 +1,16 @@
<?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">
<parent>
<artifactId>blade-ops-api</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-flow-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
</project>

View File

@ -0,0 +1,70 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.constant;
/**
* 流程常量.
*
* @author Chill
*/
public interface ProcessConstant {
/**
* 请假流程标识
*/
String LEAVE_KEY = "Leave";
/**
* 报销流程标识
*/
String EXPENSE_KEY = "Expense";
/**
* 同意标识
*/
String PASS_KEY = "pass";
/**
* 同意代号
*/
String PASS_ALIAS = "ok";
/**
* 同意默认批复
*/
String PASS_COMMENT = "同意";
/**
* 驳回默认批复
*/
String NOT_PASS_COMMENT = "驳回";
/**
* 创建人变量名
*/
String TASK_VARIABLE_CREATE_USER = "createUser";
}

View File

@ -0,0 +1,109 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.feign;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.tool.api.R;
import org.springblade.flow.core.pojo.entity.BladeFlow;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Map;
/**
* 工作流远程调用接口.
*
* @author Chill
*/
@FeignClient(
value = AppConstant.APPLICATION_FLOW_NAME,
fallback = IFlowClientFallback.class
)
public interface IFlowClient {
String API_PREFIX = "/feign/client/flow";
String START_PROCESS_INSTANCE_BY_ID = API_PREFIX + "/start-process-instance-by-id";
String START_PROCESS_INSTANCE_BY_KEY = API_PREFIX + "/start-process-instance-by-key";
String COMPLETE_TASK = API_PREFIX + "/complete-task";
String TASK_VARIABLE = API_PREFIX + "/task-variable";
String TASK_VARIABLES = API_PREFIX + "/task-variables";
/**
* 开启流程
*
* @param processDefinitionId 流程id
* @param businessKey 业务key
* @param variables 参数
* @return BladeFlow
*/
@PostMapping(START_PROCESS_INSTANCE_BY_ID)
R<BladeFlow> startProcessInstanceById(@RequestParam("processDefinitionId") String processDefinitionId, @RequestParam("businessKey") String businessKey, @RequestBody Map<String, Object> variables);
/**
* 开启流程
*
* @param processDefinitionKey 流程标识
* @param businessKey 业务key
* @param variables 参数
* @return BladeFlow
*/
@PostMapping(START_PROCESS_INSTANCE_BY_KEY)
R<BladeFlow> startProcessInstanceByKey(@RequestParam("processDefinitionKey") String processDefinitionKey, @RequestParam("businessKey") String businessKey, @RequestBody Map<String, Object> variables);
/**
* 完成任务
*
* @param taskId 任务id
* @param processInstanceId 流程实例id
* @param comment 评论
* @param variables 参数
* @return R
*/
@PostMapping(COMPLETE_TASK)
R completeTask(@RequestParam("taskId") String taskId, @RequestParam("processInstanceId") String processInstanceId, @RequestParam("comment") String comment, @RequestBody Map<String, Object> variables);
/**
* 获取流程变量
*
* @param taskId 任务id
* @param variableName 变量名
* @return R
*/
@GetMapping(TASK_VARIABLE)
R<Object> taskVariable(@RequestParam("taskId") String taskId, @RequestParam("variableName") String variableName);
/**
* 获取流程变量集合
*
* @param taskId 任务id
* @return R
*/
@GetMapping(TASK_VARIABLES)
R<Map<String, Object>> taskVariables(@RequestParam("taskId") String taskId);
}

View File

@ -0,0 +1,67 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.feign;
import org.springblade.core.tool.api.R;
import org.springblade.flow.core.pojo.entity.BladeFlow;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 流程远程调用失败处理类
*
* @author Chill
*/
@Component
public class IFlowClientFallback implements IFlowClient {
@Override
public R<BladeFlow> startProcessInstanceById(String processDefinitionId, String businessKey, Map<String, Object> variables) {
return R.fail("远程调用失败");
}
@Override
public R<BladeFlow> startProcessInstanceByKey(String processDefinitionKey, String businessKey, Map<String, Object> variables) {
return R.fail("远程调用失败");
}
@Override
public R completeTask(String taskId, String processInstanceId, String comment, Map<String, Object> variables) {
return R.fail("远程调用失败");
}
@Override
public R<Object> taskVariable(String taskId, String variableName) {
return R.fail("远程调用失败");
}
@Override
public R<Map<String, Object>> taskVariables(String taskId) {
return R.fail("远程调用失败");
}
}

View File

@ -0,0 +1,190 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.pojo.entity;
import lombok.Data;
import org.springblade.flow.core.constant.ProcessConstant;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
/**
* 工作流通用实体类
*
* @author Chill
*/
@Data
public class BladeFlow implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 任务编号
*/
private String taskId;
/**
* 任务名称
*/
private String taskName;
/**
* 任务定义Key
*/
private String taskDefinitionKey;
/**
* 任务执行人编号
*/
private String assignee;
/**
* 任务执行人名称
*/
private String assigneeName;
/**
* 流程分类
*/
private String category;
/**
* 流程分类名
*/
private String categoryName;
/**
* 创建时间
*/
private Date createTime;
/**
* 结束时间
*/
private Date endTime;
/**
* 签收时间
*/
private Date claimTime;
/**
* 历史任务结束时间
*/
private Date historyTaskEndTime;
/**
* 执行ID
*/
private String executionId;
/**
* 流程实例ID
*/
private String processInstanceId;
/**
* 流程ID
*/
private String processDefinitionId;
/**
* 流程标识
*/
private String processDefinitionKey;
/**
* 流程名
*/
private String processDefinitionName;
/**
* 流程版本
*/
private int processDefinitionVersion;
/**
* 流程说明
*/
private String processDefinitionDesc;
/**
* 流程简图名
*/
private String processDefinitionDiagramResName;
/**
* 流程重命名
*/
private String processDefinitionResName;
/**
* 历史任务流程实例ID 查看流程图会用到
*/
private String historyProcessInstanceId;
/**
* 流程实例是否结束
*/
private String processIsFinished;
/**
* 历史活动ID
*/
private String historyActivityId;
/**
* 历史活动流程
*/
private String historyActivityName;
/**
* 历史活动耗时
*/
private String historyActivityDurationTime;
/**
* 业务绑定Table
*/
private String businessTable;
/**
* 业务绑定ID
*/
private String businessId;
/**
* 任务状态
*/
private String status;
/**
* 任务意见
*/
private String comment;
/**
* 是否通过
*/
private boolean isPass;
/**
* 是否通过代号
*/
private String flag;
/**
* 开始查询日期
*/
private Date beginDate;
/**
* 结束查询日期
*/
private Date endDate;
/**
* 流程参数
*/
private Map<String, Object> variables;
/**
* 获取是否通过
*/
public boolean isPass() {
return ProcessConstant.PASS_ALIAS.equals(flag) || ProcessConstant.PASS_COMMENT.equals(comment);
}
}

View File

@ -0,0 +1,52 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.mp.base.BaseEntity;
/**
* FlowEntity
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class FlowEntity extends BaseEntity {
@TableField(exist = false)
private BladeFlow flow;
public BladeFlow getFlow() {
if (flow == null) {
flow = new BladeFlow();
}
return flow;
}
}

View File

@ -0,0 +1,54 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.pojo.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 流程类型枚举
*
* @author Chill
*/
@Getter
@AllArgsConstructor
public enum FlowModeEnum {
/**
* 通用流程
*/
COMMON("common", 1),
/**
* 定制流程
*/
CUSTOM("custom", 2),
;
final String name;
final int mode;
}

View File

@ -0,0 +1,76 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.utils;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.flow.core.constant.ProcessConstant;
import java.util.HashMap;
import java.util.Map;
/**
* 工作流工具类
*
* @author Chill
*/
public class FlowUtil {
/**
* 定义流程key对应的表名
*/
private final static Map<String, String> BUSINESS_TABLE = new HashMap<>();
static {
BUSINESS_TABLE.put(ProcessConstant.LEAVE_KEY, "blade_process_leave");
}
/**
* 通过流程key获取业务表名
*
* @param key 流程key
*/
public static String getBusinessTable(String key) {
String businessTable = BUSINESS_TABLE.get(key);
if (Func.isEmpty(businessTable)) {
return StringPool.EMPTY;
}
return businessTable;
}
/**
* 获取业务标识
*
* @param businessTable 业务表
* @param businessId 业务表主键
* @return businessKey
*/
public static String getBusinessKey(String businessTable, String businessId) {
return StringUtil.format("{}:{}", businessTable, businessId);
}
}

View File

@ -0,0 +1,80 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.flow.core.utils;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import static org.springblade.core.launch.constant.FlowConstant.TASK_USR_PREFIX;
/**
* 工作流任务工具类
*
* @author Chill
*/
public class TaskUtil {
/**
* 获取任务用户格式
*
* @return taskUser
*/
public static String getTaskUser() {
return StringUtil.format("{}{}", TASK_USR_PREFIX, AuthUtil.getUserId());
}
/**
* 获取任务用户格式
*
* @param userId 用户id
* @return taskUser
*/
public static String getTaskUser(String userId) {
return StringUtil.format("{}{}", TASK_USR_PREFIX, userId);
}
/**
* 获取用户主键
*
* @param taskUser 任务用户
* @return userId
*/
public static Long getUserId(String taskUser) {
return Func.toLong(StringUtil.removePrefix(taskUser, TASK_USR_PREFIX));
}
/**
* 获取用户组格式
*
* @return candidateGroup
*/
public static String getCandidateGroup() {
return AuthUtil.getUserRole();
}
}

View File

@ -0,0 +1,27 @@
<?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">
<parent>
<artifactId>blade-ops-api</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-resource-api</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-sms</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-tenant</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,119 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.feign;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.sms.model.SmsResponse;
import org.springblade.core.tool.api.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* ISmsClient
*
* @author Chill
*/
@FeignClient(
value = AppConstant.APPLICATION_RESOURCE_NAME,
fallback = ISmsClientFallback.class
)
public interface ISmsClient {
String API_PREFIX = "/feign/client/sms";
String SEND_MESSAGE = API_PREFIX + "/send-message";
String SEND_MESSAGE_BY_TENANT_ID = API_PREFIX + "/send-message-by-tenant-id";
String SEND_VALIDATE = API_PREFIX + "/send-validate";
String SEND_VALIDATE_BY_TENANT_ID = API_PREFIX + "/send-validate-by-tenant-id";
String VALIDATE_MESSAGE = API_PREFIX + "/validate-message";
String VALIDATE_MESSAGE_BY_TENANT_ID = API_PREFIX + "/validate-message-by-tenant-id";
/**
* 通用短信发送
*
* @param code 资源编号
* @param params 模板参数
* @param phones 手机号集合
* @return R
*/
@PostMapping(SEND_MESSAGE)
R<SmsResponse> sendMessage(@RequestParam("code") String code, @RequestParam("params") String params, @RequestParam("phones") String phones);
/**
* 通用短信发送
*
* @param code 资源编号
* @param params 模板参数
* @param phones 手机号集合
* @return R
*/
@PostMapping(SEND_MESSAGE_BY_TENANT_ID)
R<SmsResponse> sendMessage(@RequestParam("tenantId") String tenantId, @RequestParam("code") String code, @RequestParam("params") String params, @RequestParam("phones") String phones);
/**
* 短信验证码发送
*
* @param code 资源编号
* @param phone 手机号
* @return R
*/
@PostMapping(SEND_VALIDATE)
R sendValidate(@RequestParam("code") String code, @RequestParam("phone") String phone);
/**
* 短信验证码发送
*
* @param code 资源编号
* @param phone 手机号
* @return R
*/
@PostMapping(SEND_VALIDATE_BY_TENANT_ID)
R sendValidate(@RequestParam("tenantId") String tenantId, @RequestParam("code") String code, @RequestParam("phone") String phone);
/**
* 校验短信
*
* @param code 资源编号
* @param id 校验id
* @param value 校验值
* @param phone 手机号
* @return R
*/
@PostMapping(VALIDATE_MESSAGE)
R validateMessage(@RequestParam("code") String code, @RequestParam("id") String id, @RequestParam("value") String value, @RequestParam("phone") String phone);
/**
* 校验短信
*
* @param code 资源编号
* @param id 校验id
* @param value 校验值
* @param phone 手机号
* @return R
*/
@PostMapping(VALIDATE_MESSAGE_BY_TENANT_ID)
R validateMessage(@RequestParam("tenantId") String tenantId, @RequestParam("code") String code, @RequestParam("id") String id, @RequestParam("value") String value, @RequestParam("phone") String phone);
}

View File

@ -0,0 +1,69 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.feign;
import org.springblade.core.sms.model.SmsResponse;
import org.springblade.core.tool.api.R;
import org.springframework.stereotype.Component;
/**
* 流程远程调用失败处理类
*
* @author Chill
*/
@Component
public class ISmsClientFallback implements ISmsClient {
@Override
public R<SmsResponse> sendMessage(String code, String params, String phones) {
return R.fail("远程调用失败");
}
@Override
public R<SmsResponse> sendMessage(String tenantId, String code, String params, String phones) {
return R.fail("远程调用失败");
}
@Override
public R sendValidate(String code, String phone) {
return R.fail("远程调用失败");
}
@Override
public R sendValidate(String tenantId, String code, String phone) {
return R.fail("远程调用失败");
}
@Override
public R validateMessage(String code, String id, String value, String phone) {
return R.fail("远程调用失败");
}
@Override
public R validateMessage(String tenantId, String code, String id, String value, String phone) {
return R.fail("远程调用失败");
}
}

View File

@ -0,0 +1,82 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.io.Serial;
/**
* 附件表实体类
*
* @author Chill
*/
@Data
@TableName("blade_attach")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "附件表")
public class Attach extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 附件地址
*/
@Schema(description = "附件地址")
private String link;
/**
* 附件域名
*/
@Schema(description = "附件域名")
private String domainUrl;
/**
* 附件名称
*/
@Schema(description = "附件名称")
private String name;
/**
* 附件原名
*/
@Schema(description = "附件原名")
private String originalName;
/**
* 附件拓展名
*/
@Schema(description = "附件拓展名")
private String extension;
/**
* 附件大小
*/
@Schema(description = "附件大小")
private Long attachSize;
}

View File

@ -0,0 +1,108 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springblade.core.tool.jackson.Sensitive;
import org.springblade.core.tool.sensitive.SensitiveType;
import java.io.Serial;
/**
* 实体类
*
* @author BladeX
*/
@Data
@TableName("blade_oss")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "Oss对象")
public class Oss extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 所属分类
*/
@Schema(description = "所属分类")
private Integer category;
/**
* 资源编号
*/
@Schema(description = "资源编号")
private String ossCode;
/**
* 资源地址
*/
@Schema(description = "资源地址")
private String endpoint;
/**
* 外网资源地址
*/
@Schema(description = "外网资源地址")
private String transformEndpoint;
/**
* accessKey
*/
@Sensitive(type = SensitiveType.KEYS)
@Schema(description = "accessKey")
private String accessKey;
/**
* secretKey
*/
@Sensitive(type = SensitiveType.KEYS)
@Schema(description = "secretKey")
private String secretKey;
/**
* 空间名
*/
@Schema(description = "空间名")
private String bucketName;
/**
* 应用ID TencentCOS需要
*/
@Schema(description = "应用ID")
private String appId;
/**
* 地域简称 TencentCOS需要
*/
@Schema(description = "地域简称")
private String region;
/**
* 备注
*/
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,102 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springblade.core.tool.jackson.Sensitive;
import org.springblade.core.tool.sensitive.SensitiveType;
import java.io.Serial;
/**
* 短信配置表实体类
*
* @author BladeX
*/
@Data
@TableName("blade_sms")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "短信配置表")
public class Sms extends TenantEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 资源编号
*/
@Schema(description = "资源编号")
private String smsCode;
/**
* 模板ID
*/
@Schema(description = "模板ID")
private String templateId;
/**
* 分类
*/
@Schema(description = "分类")
private Integer category;
/**
* accessKey
*/
@Sensitive(type = SensitiveType.KEYS)
@Schema(description = "accessKey")
private String accessKey;
/**
* secretKey
*/
@Sensitive(type = SensitiveType.KEYS)
@Schema(description = "secretKey")
private String secretKey;
/**
* regionId
*/
@Schema(description = "regionId")
private String regionId;
/**
* appId
*/
@Schema(description = "appId")
private String appId;
/**
* 短信签名
*/
@Schema(description = "短信签名")
private String signName;
/**
* 备注
*/
@Schema(description = "备注")
private String remark;
}

View File

@ -0,0 +1,71 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springblade.core.tool.utils.StringPool;
/**
* Sms资源编码枚举类
*
* @author Chill
* @apiNote 该枚举类对应短信配置模块的资源编码可根据业务需求自行拓展
*/
@Getter
@AllArgsConstructor
public enum SmsCodeEnum {
/**
* 默认编号
*/
DEFAULT(StringPool.EMPTY, 1),
/**
* 验证码编号
*/
VALIDATE("validate", 2),
/**
* 通知公告编号
*/
NOTICE("notice", 3),
/**
* 下单通知编号
*/
ORDER("order", 4),
/**
* 会议通知编号
*/
MEETING("meeting", 5),
;
final String name;
final int category;
}

View File

@ -0,0 +1,47 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.resource.pojo.entity.Attach;
import java.io.Serial;
/**
* 附件表视图实体类
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "附件表")
public class AttachVO extends Attach {
@Serial
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,32 @@
package org.springblade.resource.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.resource.pojo.entity.Oss;
import java.io.Serial;
/**
* OssVO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "对象存储表")
public class OssVO extends Oss {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分类名
*/
private String categoryName;
/**
* 是否启用
*/
private String statusName;
}

View File

@ -0,0 +1,57 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.pojo.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.resource.pojo.entity.Sms;
import java.io.Serial;
/**
* 短信配置表视图实体类
*
* @author BladeX
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "短信配置表")
public class SmsVO extends Sms {
@Serial
private static final long serialVersionUID = 1L;
/**
* 分类名
*/
private String categoryName;
/**
* 是否启用
*/
private String statusName;
}

View File

@ -0,0 +1,122 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.resource.utils;
import org.springblade.core.sms.model.SmsCode;
import org.springblade.core.sms.model.SmsResponse;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.RandomType;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.resource.feign.ISmsClient;
import java.util.HashMap;
import java.util.Map;
/**
* 短信服务工具类
*
* @author Chill
*/
public class SmsUtil {
public static final String PARAM_KEY = "code";
public static final String SEND_SUCCESS = "短信发送成功";
public static final String SEND_FAIL = "短信发送失败";
public static final String VALIDATE_SUCCESS = "短信校验成功";
public static final String VALIDATE_FAIL = "短信校验失败";
private static ISmsClient smsClient;
/**
* 获取短信服务构建类
*
* @return SmsBuilder
*/
public static ISmsClient getSmsClient() {
if (smsClient == null) {
smsClient = SpringUtil.getBean(ISmsClient.class);
}
return smsClient;
}
/**
* 获取短信验证码参数
*
* @return 验证码参数
*/
public static Map<String, String> getValidateParams() {
Map<String, String> params = new HashMap<>(1);
params.put(PARAM_KEY, StringUtil.random(6, RandomType.INT));
return params;
}
/**
* 发送短信
*
* @param code 资源编号
* @param params 模板参数
* @param phones 手机号集合
* @return 发送结果
*/
public static SmsResponse sendMessage(String code, Map<String, String> params, String phones) {
R<SmsResponse> result = getSmsClient().sendMessage(code, JsonUtil.toJson(params), phones);
return result.getData();
}
/**
* 发送验证码
*
* @param code 资源编号
* @param phone 手机号
* @return 发送结果
*/
public static SmsCode sendValidate(String code, String phone) {
SmsCode smsCode = new SmsCode();
R result = getSmsClient().sendValidate(code, phone);
if (result.isSuccess()) {
smsCode = JsonUtil.parse(JsonUtil.toJson(result.getData()), SmsCode.class);
} else {
smsCode.setSuccess(Boolean.FALSE);
}
return smsCode;
}
/**
* 校验短信
*
* @param code 资源编号
* @param id 校验id
* @param value 校验值
* @return 发送结果
*/
public static boolean validateMessage(String code, String id, String value, String phone) {
R result = getSmsClient().validateMessage(code, id, value, phone);
return result.isSuccess();
}
}

52
blade-ops-api/pom.xml Normal file
View File

@ -0,0 +1,52 @@
<?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">
<parent>
<artifactId>BladeX</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-ops-api</artifactId>
<name>${project.artifactId}</name>
<packaging>pom</packaging>
<description>BladeX 微服务API集合</description>
<modules>
<module>blade-flow-api</module>
<module>blade-resource-api</module>
<module>blade-develop-api</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
<finalName>${project.name}</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,15 @@
FROM bladex/alpine-java:openjdk17_cn_slim
LABEL maintainer="bladejava@qq.com"
RUN mkdir -p /blade/admin
WORKDIR /blade/admin
EXPOSE 7002
COPY ./target/blade-admin.jar ./app.jar
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]

View File

@ -0,0 +1,21 @@
## SDK下载
#### Java SDK 下载
下载SDK: https://open-doc.dingtalk.com/microapp/faquestions/vzbp02
## 配置项
#### bootstrap.yml
```
# 监控的相关配置
monitor:
ding-talk:
enabled: false
# 用于自定义域名,默认会自动填充为 http://ip:port
link: http://localhost:${server.port}
# 钉钉配置的令牌
access-token: xxx
# 如果采用密钥形式,需要添加,否则需要去掉该参数
secret: xxx
```

View File

@ -0,0 +1,109 @@
<?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">
<parent>
<artifactId>blade-ops</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-admin</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<!--Blade-->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId>
<exclusions>
<exclusion>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-prometheus</artifactId>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
<!--Admin-Server-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<!--Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</dependency>-->
<!--Taobao-Sdk-->
<dependency>
<groupId>com.taobao</groupId>
<artifactId>taobao-sdk</artifactId>
<version>20201116</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>${docker.fabric.skip}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,48 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.admin;
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springblade.core.launch.BladeApplication;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* admin启动器
*
* @author Chill
*/
@EnableAdminServer
@EnableDiscoveryClient
@SpringBootApplication
public class AdminApplication {
public static void main(String[] args) {
BladeApplication.run(AppConstant.APPLICATION_ADMIN_NAME, AdminApplication.class, args);
}
}

View File

@ -0,0 +1,41 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.admin.config;
import org.springblade.admin.dingtalk.MonitorProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 启动器
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(MonitorProperties.class)
public class AdminConfiguration {
}

View File

@ -0,0 +1,61 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.admin.config;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import org.springblade.admin.dingtalk.DingTalkNotifier;
import org.springblade.admin.dingtalk.DingTalkService;
import org.springblade.admin.dingtalk.MonitorProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.reactive.function.client.WebClient;
/**
* 钉钉自动配置
*
* @author L.cm
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "monitor.ding-talk.enabled", havingValue = "true")
public class DingTalkConfiguration {
@Bean
public DingTalkService dingTalkService(MonitorProperties properties,
WebClient.Builder builder) {
return new DingTalkService(properties, builder.build());
}
@Bean
public DingTalkNotifier dingTalkNotifier(MonitorProperties properties,
DingTalkService dingTalkService,
InstanceRepository repository,
Environment environment) {
return new DingTalkNotifier(dingTalkService, properties, environment, repository);
}
}

View File

@ -0,0 +1,96 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.admin.config;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springblade.admin.security.InternalAuthorizationManager;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import java.net.URI;
/**
* 监控安全配置
*
* @author L.cm
*/
@EnableWebFluxSecurity
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AdminServerProperties.class)
public class SecurityConfiguration {
private final String contextPath;
public SecurityConfiguration(AdminServerProperties adminServerProperties) {
this.contextPath = adminServerProperties.getContextPath();
}
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// @formatter:off
RedirectServerAuthenticationSuccessHandler successHandler = new RedirectServerAuthenticationSuccessHandler();
successHandler.setLocation(URI.create(contextPath + "/"));
return http
// 明确调用headers()方法进行配置
.headers(headers -> headers
// 禁用frameOptions
.frameOptions(ServerHttpSecurity.HeaderSpec.FrameOptionsSpec::disable)
)
// 配置授权规则
.authorizeExchange(exchanges -> exchanges
.pathMatchers(
contextPath + "/assets/**",
contextPath + "/login",
contextPath + "/v1/agent/**",
contextPath + "/v1/catalog/**",
contextPath + "/v1/health/**"
).permitAll()
.pathMatchers(contextPath + "/actuator", contextPath + "/actuator/**")
.access(new InternalAuthorizationManager())
.anyExchange().authenticated()
)
// 配置表单登录
.formLogin(formLogin -> formLogin
.loginPage(contextPath + "/login")
.authenticationSuccessHandler(successHandler)
)
// 配置登出
.logout(logout -> logout
.logoutUrl(contextPath + "/logout")
)
// 禁用HTTP Basic认证
.httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
// 禁用CSRF
.csrf(ServerHttpSecurity.CsrfSpec::disable)
.build();
// @formatter:on
}
}

View File

@ -0,0 +1,114 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.admin.dingtalk;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.domain.values.StatusInfo;
import de.codecentric.boot.admin.server.notify.AbstractEventNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
/**
* 服务上下线告警
*
* <p>
* 注意AbstractStatusChangeNotifier 这个事件有毛病
* </p>
*
* @author L.cm
*/
@Slf4j
public class DingTalkNotifier extends AbstractEventNotifier {
private final DingTalkService dingTalkService;
private final MonitorProperties properties;
private final Environment environment;
public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public DingTalkNotifier(DingTalkService dingTalkService, MonitorProperties properties,
Environment environment, InstanceRepository repository) {
super(repository);
this.dingTalkService = dingTalkService;
this.properties = properties;
this.environment = environment;
}
@NonNull
@Override
protected Mono<Void> doNotify(@NonNull InstanceEvent event, @NonNull Instance instance) {
if (event instanceof InstanceStatusChangedEvent) {
// 构造请求结构
return createAndPushMsg(event, instance);
}
return Mono.empty();
}
private Mono<Void> createAndPushMsg(InstanceEvent event, Instance instance) {
Registration registration = instance.getRegistration();
// 服务名
String appName = registration.getName();
// 服务地址
String serviceUrl = registration.getServiceUrl();
StatusInfo status = instance.getStatusInfo();
// 时间
LocalDateTime localDateTime = LocalDateTime.ofInstant(event.getTimestamp(), ZoneId.systemDefault());
MonitorProperties.DingTalk dingTalk = properties.getDingTalk();
String title = dingTalk.getService().getTitle();
String message = "## **" + title + "**\n" +
"#### **【服务】** " + appName + "\n" +
"#### **【环境】** " + environment.getActiveProfiles()[0] + "\n" +
"#### **【地址】** " + serviceUrl + "\n" +
"#### **【状态】** " + statusCn(status) + "\n" +
"#### **【时间】** " + DATETIME_FORMATTER.format(localDateTime) + "\n" +
"#### **【详情】** " + dingTalk.getLink() + "\n";
return dingTalkService.pushMsg(title, message);
}
private String statusCn(StatusInfo status) {
if (status.isUp()) {
return "应用上线IS UP";
} else if (status.isDown()) {
return "应用宕机IS DOWN";
} else if (status.isOffline()) {
return "应用掉线IS OFFLINE";
} else if (status.isUnknown()) {
return "未知状态UNKNOWN";
} else {
return "异常状态";
}
}
}

View File

@ -0,0 +1,119 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: DreamLu (596392912@qq.com)
*/
package org.springblade.admin.dingtalk;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriUtils;
import reactor.core.publisher.Mono;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉 服务
*
* @author L.cm
*/
@Slf4j
@RequiredArgsConstructor
public class DingTalkService {
private static final String DING_TALK_ROBOT_URL = "https://oapi.dingtalk.com/robot/send?access_token=";
private final MonitorProperties properties;
private final WebClient webClient;
/**
* 发送消息
*
* @param title title
* @param text 消息
*/
public Mono<Void> pushMsg(String title, String text) {
log.info("钉钉消息:[创建消息体]title:{}, text:{}", title, text);
HashMap<String, String> params = new HashMap<>(2);
params.put("title", title);
params.put("text", text);
Map<String, Object> body = new HashMap<>(2);
body.put("msgtype", "markdown");
body.put("markdown", params);
log.info("创建消息体 json{}", body);
MonitorProperties.DingTalk dingTalk = properties.getDingTalk();
String accessToken = dingTalk.getAccessToken();
if (!StringUtils.hasText(accessToken)) {
log.error("DingTalk alert config accessToken ${monitor.ding-talk.access-token} is blank.");
return Mono.empty();
}
String urlString = DING_TALK_ROBOT_URL + dingTalk.getAccessToken();
// 有私钥要签名
String secret = dingTalk.getSecret();
if (StringUtils.hasText(secret)) {
long timestamp = System.currentTimeMillis();
urlString += String.format("&timestamp=%s&sign=%s", timestamp, getSign(secret, timestamp));
}
return webClient.post()
.uri(URI.create(urlString))
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(body))
.retrieve()
.bodyToMono(String.class)
.doOnSuccess((result) -> log.info("钉钉消息:[消息返回]result:{}", result))
.then();
}
private static String getSign(String secret, long timestamp) {
String stringToSign = timestamp + "\n" + secret;
byte[] hmacSha256Bytes = digestHmac(stringToSign, secret);
return UriUtils.encode(Base64.getEncoder().encodeToString(hmacSha256Bytes), StandardCharsets.UTF_8);
}
public static byte[] digestHmac(String data, String key) {
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
try {
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
mac.init(secretKey);
return mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e.getMessage());
}
}
}

Some files were not shown because too many files have changed in this diff Show More