init
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<?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>blade-core-auth</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-key</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<module.name>org.springblade.blade.starter.key</module.name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-tool</artifactId>
|
||||
</dependency>
|
||||
<!-- Auto -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+109
@@ -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.core.secure;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springblade.core.tool.support.Kv;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户实体
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@Hidden
|
||||
public class BladeUser implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private Long userId;
|
||||
/**
|
||||
* 账号
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String account;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String userName;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String nickName;
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String tenantId;
|
||||
/**
|
||||
* 第三方认证ID
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String oauthId;
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String deptId;
|
||||
/**
|
||||
* 岗位id
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String postId;
|
||||
/**
|
||||
* 角色id
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String roleId;
|
||||
/**
|
||||
* 角色名
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private String roleName;
|
||||
/**
|
||||
* 用户详情
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
private Kv detail;
|
||||
|
||||
}
|
||||
+155
@@ -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.core.secure;
|
||||
|
||||
import org.springblade.core.secure.constant.ApiKeyConstant;
|
||||
import org.springblade.core.tool.utils.Charsets;
|
||||
import org.springblade.core.tool.utils.Exceptions;
|
||||
import org.springblade.core.tool.utils.HexUtil;
|
||||
import org.springblade.core.tool.utils.Pkcs7Encoder;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Key加解密工具类
|
||||
*
|
||||
* @author BladeX
|
||||
*/
|
||||
public class KeyCrypto {
|
||||
public static final Charset DEFAULT_CHARSET = Charsets.UTF_8;
|
||||
|
||||
public static String genAesKey() {
|
||||
return StringUtil.random(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 API Key
|
||||
*
|
||||
* @param cryptoKey 加密密钥
|
||||
* @return 带前缀的加密 Key
|
||||
*/
|
||||
public static String generateKey(String cryptoKey) {
|
||||
return ApiKeyConstant.API_KEY_PREFIX + encryptToHex(StringUtil.randomUUID(), cryptoKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 API Key
|
||||
*
|
||||
* @param key 带前缀的加密 Key
|
||||
* @param cryptoKey 加密密钥
|
||||
* @return 解密后的原始值
|
||||
*/
|
||||
@Nullable
|
||||
public static String parseKey(@Nullable String key, String cryptoKey) {
|
||||
if (StringUtil.isBlank(key) || !key.startsWith(ApiKeyConstant.API_KEY_PREFIX)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String encryptedPart = key.substring(ApiKeyConstant.API_KEY_PREFIX.length());
|
||||
return decryptFormHexToString(encryptedPart, cryptoKey);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String encryptToHex(String content, String aesTextKey) {
|
||||
return HexUtil.encodeToString(encrypt(content, aesTextKey));
|
||||
}
|
||||
|
||||
public static String encryptToHex(byte[] content, String aesTextKey) {
|
||||
return HexUtil.encodeToString(encrypt(content, aesTextKey));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String decryptFormHexToString(@Nullable String content, String aesTextKey) {
|
||||
byte[] hexBytes = decryptFormHex(content, aesTextKey);
|
||||
if (hexBytes == null) {
|
||||
return null;
|
||||
}
|
||||
return new String(hexBytes, DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static byte[] decryptFormHex(@Nullable String content, String aesTextKey) {
|
||||
if (StringUtil.isBlank(content)) {
|
||||
return null;
|
||||
}
|
||||
return decryptFormHex(content.getBytes(DEFAULT_CHARSET), aesTextKey);
|
||||
}
|
||||
|
||||
public static byte[] decryptFormHex(byte[] content, String aesTextKey) {
|
||||
return decrypt(HexUtil.decode(content), aesTextKey);
|
||||
}
|
||||
|
||||
public static byte[] encrypt(String content, String aesTextKey) {
|
||||
return encrypt(content.getBytes(DEFAULT_CHARSET), aesTextKey);
|
||||
}
|
||||
|
||||
public static byte[] encrypt(String content, Charset charset, String aesTextKey) {
|
||||
return encrypt(content.getBytes(charset), aesTextKey);
|
||||
}
|
||||
|
||||
public static byte[] encrypt(byte[] content, String aesTextKey) {
|
||||
return encrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
|
||||
}
|
||||
|
||||
public static byte[] encrypt(byte[] content, byte[] aesKey) {
|
||||
return aes(Pkcs7Encoder.encode(content), aesKey, Cipher.ENCRYPT_MODE);
|
||||
}
|
||||
|
||||
public static String decryptToString(byte[] content, String aesTextKey) {
|
||||
return new String(decrypt(content, aesTextKey), DEFAULT_CHARSET);
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] content, String aesTextKey) {
|
||||
return decrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
|
||||
}
|
||||
|
||||
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
|
||||
return Pkcs7Encoder.decode(aes(encrypted, aesKey, Cipher.DECRYPT_MODE));
|
||||
}
|
||||
|
||||
private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
|
||||
Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
|
||||
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
|
||||
cipher.init(mode, keySpec, iv);
|
||||
return cipher.doFinal(encrypted);
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.unchecked(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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.core.secure.constant;
|
||||
|
||||
/**
|
||||
* API Key 常量
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface ApiKeyConstant {
|
||||
|
||||
/**
|
||||
* API Key 前缀
|
||||
*/
|
||||
String API_KEY_PREFIX = "ak-";
|
||||
|
||||
/**
|
||||
* 启用状态
|
||||
*/
|
||||
int STATUS_ACTIVE = 1;
|
||||
|
||||
/**
|
||||
* 缓存名称
|
||||
*/
|
||||
String API_KEY_CACHE = "blade:apikey";
|
||||
|
||||
/**
|
||||
* 用户缓存前缀
|
||||
*/
|
||||
String CACHE_USER_PREFIX = "apikey:user:";
|
||||
|
||||
/**
|
||||
* 路径缓存前缀
|
||||
*/
|
||||
String CACHE_PATH_PREFIX = "apikey:path:";
|
||||
|
||||
/**
|
||||
* 全路径匹配
|
||||
*/
|
||||
String FULL_PATH = "/**";
|
||||
|
||||
/**
|
||||
* 角色名称列名
|
||||
*/
|
||||
String ROLE_NAME_COLUMN = "role_name";
|
||||
|
||||
/**
|
||||
* 角色别名列名
|
||||
*/
|
||||
String ROLE_ALIAS_COLUMN = "role_alias";
|
||||
|
||||
/**
|
||||
* BladeUser.detail 中存放 API Key 主键ID 的 key
|
||||
*/
|
||||
String DETAIL_API_KEY_ID = "apiKeyId";
|
||||
|
||||
// ====================================================================
|
||||
// SQL 查询语句(分步查询策略)
|
||||
// 采用多步单表查询而非联表查询,防止大数据量用户表联查导致查询速度过慢
|
||||
// ====================================================================
|
||||
|
||||
/**
|
||||
* 查询 API Key 基本信息(第一步:仅查 blade_api_key 表)
|
||||
*/
|
||||
String API_KEY_SELECT_STATEMENT = """
|
||||
SELECT id, tenant_id, user_id, api_key, api_path, expire_time, ext_params, status
|
||||
FROM blade_api_key WHERE api_key = ? AND status = 1 AND is_deleted = 0
|
||||
""";
|
||||
|
||||
/**
|
||||
* 查询关联用户信息(第二步:通过 userId 查 blade_user 表)
|
||||
*/
|
||||
String API_KEY_USER_SELECT_STATEMENT = """
|
||||
SELECT account, name, real_name, dept_id, post_id, role_id
|
||||
FROM blade_user WHERE id = ? AND status = 1 AND is_deleted = 0
|
||||
""";
|
||||
|
||||
/**
|
||||
* 查询角色名称与别名(第三步:通过 roleId 查 blade_role 表,%s 由代码动态填充 IN 列表)
|
||||
*/
|
||||
String API_KEY_ROLE_SELECT_STATEMENT = """
|
||||
SELECT role_name, role_alias FROM blade_role WHERE is_deleted = 0 AND status = 1 AND id IN (%s)
|
||||
""";
|
||||
|
||||
// ====================================================================
|
||||
// 调用日志持久化
|
||||
// ====================================================================
|
||||
|
||||
/**
|
||||
* 插入 API Key 调用日志
|
||||
*/
|
||||
String API_KEY_LOG_INSERT = """
|
||||
INSERT INTO blade_api_key_log
|
||||
(id, tenant_id, service_id, server_ip, server_host, env, api_key_id, request_uri, method, remote_ip, user_agent, params, time, create_by, create_time)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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.core.secure.env;
|
||||
|
||||
import org.springblade.core.auto.annotation.AutoEnvPostProcessor;
|
||||
import org.springblade.core.launch.utils.PropsUtil;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* 超级密钥配置初始化。
|
||||
* <p>
|
||||
* 微服务侧 (存在 blade-core-cloud) 将 {@code path-prefix} 落值为服务名,路径校验时补回网关剥离的前缀,
|
||||
* 使 api_path 配置在单体与微服务下语义一致。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AutoEnvPostProcessor
|
||||
public class KeyEnvPostProcessor implements EnvironmentPostProcessor, Ordered {
|
||||
|
||||
private static final String PATH_PREFIX_KEY = "blade.key.path-prefix";
|
||||
|
||||
private static final String APPLICATION_NAME_KEY = "spring.application.name";
|
||||
|
||||
/**
|
||||
* 是否微服务部署: 存在 blade-core-cloud 即经网关按服务名路由
|
||||
*/
|
||||
private static final boolean MICROSERVICE = ClassUtils.isPresent(
|
||||
"org.springblade.core.cloud.client.BladeCloudApplication", KeyEnvPostProcessor.class.getClassLoader());
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
String serviceName = environment.getProperty(APPLICATION_NAME_KEY, StringPool.EMPTY);
|
||||
if (MICROSERVICE && StringUtil.isNotBlank(serviceName) && StringUtil.isBlank(environment.getProperty(PATH_PREFIX_KEY))) {
|
||||
PropsUtil.setProperty(System.getProperties(), PATH_PREFIX_KEY, StringPool.SLASH.concat(serviceName));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* 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.core.secure.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springblade.core.tool.api.IResultCode;
|
||||
import org.springblade.core.tool.api.ResultCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* Key异常
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class KeyException extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Getter
|
||||
private final IResultCode resultCode;
|
||||
|
||||
public KeyException(String message) {
|
||||
super(message);
|
||||
this.resultCode = ResultCode.UN_AUTHORIZED;
|
||||
}
|
||||
|
||||
public KeyException(IResultCode resultCode) {
|
||||
super(resultCode.getMessage());
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
public KeyException(IResultCode resultCode, Throwable cause) {
|
||||
super(cause);
|
||||
this.resultCode = resultCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+96
@@ -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: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.secure.handler;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springblade.core.launch.constant.TokenConstant;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springblade.core.secure.constant.ApiKeyConstant;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.core.tool.utils.WebUtil;
|
||||
|
||||
/**
|
||||
* API Key 处理器接口
|
||||
* 用于通过 API Key 获取用户信息
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface IApiKeyHandler {
|
||||
|
||||
/**
|
||||
* 通过 API Key 获取用户信息
|
||||
*
|
||||
* @param apiKey API Key (ak-xxx格式)
|
||||
* @return BladeUser 用户信息,若不存在或已过期则返回 null
|
||||
*/
|
||||
BladeUser getUser(String apiKey);
|
||||
|
||||
/**
|
||||
* 移除 API Key 相关缓存
|
||||
*
|
||||
* @param apiKey API Key
|
||||
*/
|
||||
void removeCache(String apiKey);
|
||||
|
||||
/**
|
||||
* 生成 API Key
|
||||
* 格式: ak-[UUID无中划线]
|
||||
*
|
||||
* @return 生成的 API Key
|
||||
*/
|
||||
default String generateKey() {
|
||||
return ApiKeyConstant.API_KEY_PREFIX + StringUtil.randomUUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的认证字符串是否为有效的 API Key
|
||||
*
|
||||
* @param auth 认证字符串
|
||||
* @return true 如果是有效的 API Key,否则返回 false
|
||||
*/
|
||||
default boolean isApiKey(String auth) {
|
||||
return StringUtil.isNotBlank(auth) && auth.startsWith(ApiKeyConstant.API_KEY_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前请求是否包含有效的 API Key
|
||||
*
|
||||
* @return true 如果请求中包含有效的 API Key,否则返回 false
|
||||
*/
|
||||
default boolean isApiKeyRequest() {
|
||||
HttpServletRequest request = WebUtil.getRequest();
|
||||
if (request == null) {
|
||||
return false;
|
||||
}
|
||||
String auth = request.getHeader(TokenConstant.AUTH_HEADER);
|
||||
if (StringUtil.isBlank(auth)) {
|
||||
auth = request.getParameter(TokenConstant.AUTH_HEADER);
|
||||
}
|
||||
return isApiKey(auth);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+54
@@ -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.core.secure.handler;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springblade.core.secure.BladeUser;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* API Key 调用日志处理器接口
|
||||
* <p>
|
||||
* 下游工程可自定义实现以支持不同的日志存储策略(如消息队列、远程服务等)。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface IApiKeyLogHandler {
|
||||
|
||||
/**
|
||||
* 保存 API Key 调用日志
|
||||
* <p>
|
||||
* 该方法在主请求线程中调用,实现类可在内部自行决定同步或异步策略。
|
||||
* request 由调用方在主线程中获取后传入,实现类无需再通过线程上下文获取。
|
||||
*
|
||||
* @param bladeUser 认证通过的用户信息
|
||||
* @param apiKeyId API Key 主键ID
|
||||
* @param time 认证耗时(ms)
|
||||
* @param request 当前请求对象(可能为空)
|
||||
*/
|
||||
void saveLog(BladeUser bladeUser, Long apiKeyId, long time, @Nullable HttpServletRequest request);
|
||||
|
||||
}
|
||||
+68
@@ -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.core.secure.props;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springblade.core.secure.exception.KeyException;
|
||||
import org.springblade.core.tool.utils.StringPool;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 超级密钥配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties("blade.key")
|
||||
public class KeyProperties {
|
||||
|
||||
/**
|
||||
* 超级密钥是否开启
|
||||
*/
|
||||
private Boolean enabled = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 超级密钥
|
||||
*/
|
||||
private String cryptoKey = StringPool.EMPTY;
|
||||
|
||||
/**
|
||||
* 路径校验前缀 (微服务侧由 KeyEnvPostProcessor 落值为服务名,单体为空)
|
||||
*/
|
||||
private String pathPrefix = StringPool.EMPTY;
|
||||
|
||||
/**
|
||||
* 获取超级密钥
|
||||
*/
|
||||
public String getCryptoKey() {
|
||||
if (StringUtil.isBlank(cryptoKey)) {
|
||||
throw new KeyException("请配置 blade.key.crypto-key 的值");
|
||||
}
|
||||
return this.cryptoKey;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user