mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: app password use ciphertext
This commit is contained in:
parent
e711ed7251
commit
eb4d7ab8eb
@ -11,6 +11,7 @@ import tech.powerjob.client.service.PowerRequestBody;
|
|||||||
import tech.powerjob.client.service.RequestService;
|
import tech.powerjob.client.service.RequestService;
|
||||||
import tech.powerjob.client.service.impl.ClusterRequestServiceOkHttp3Impl;
|
import tech.powerjob.client.service.impl.ClusterRequestServiceOkHttp3Impl;
|
||||||
import tech.powerjob.common.OpenAPIConstant;
|
import tech.powerjob.common.OpenAPIConstant;
|
||||||
|
import tech.powerjob.common.enums.EncryptType;
|
||||||
import tech.powerjob.common.enums.InstanceStatus;
|
import tech.powerjob.common.enums.InstanceStatus;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
import tech.powerjob.common.request.http.SaveJobInfoRequest;
|
||||||
@ -53,6 +54,7 @@ public class PowerJobClient implements IPowerJobClient {
|
|||||||
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
||||||
appAuthRequest.setAppName(appName);
|
appAuthRequest.setAppName(appName);
|
||||||
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
||||||
|
appAuthRequest.setEncryptType(EncryptType.MD5.getCode());
|
||||||
|
|
||||||
String assertResponse = requestService.request(OpenAPIConstant.AUTH_APP, PowerRequestBody.newJsonRequestBody(appAuthRequest));
|
String assertResponse = requestService.request(OpenAPIConstant.AUTH_APP, PowerRequestBody.newJsonRequestBody(appAuthRequest));
|
||||||
|
|
||||||
|
@ -26,6 +26,12 @@ public class AppAuthRequest implements Serializable {
|
|||||||
* 加密后密码
|
* 加密后密码
|
||||||
*/
|
*/
|
||||||
private String encryptedPassword;
|
private String encryptedPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密类型
|
||||||
|
*/
|
||||||
|
private String encryptType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 额外参数,方便开发者传递其他参数
|
* 额外参数,方便开发者传递其他参数
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@ import tech.powerjob.client.module.AppAuthResult;
|
|||||||
import tech.powerjob.client.service.HttpResponse;
|
import tech.powerjob.client.service.HttpResponse;
|
||||||
import tech.powerjob.client.service.PowerRequestBody;
|
import tech.powerjob.client.service.PowerRequestBody;
|
||||||
import tech.powerjob.common.OpenAPIConstant;
|
import tech.powerjob.common.OpenAPIConstant;
|
||||||
|
import tech.powerjob.common.enums.EncryptType;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
import tech.powerjob.common.response.ResultDTO;
|
import tech.powerjob.common.response.ResultDTO;
|
||||||
import tech.powerjob.common.utils.DigestUtils;
|
import tech.powerjob.common.utils.DigestUtils;
|
||||||
@ -95,6 +96,7 @@ abstract class AppAuthClusterRequestService extends ClusterRequestService {
|
|||||||
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
AppAuthRequest appAuthRequest = new AppAuthRequest();
|
||||||
appAuthRequest.setAppName(config.getAppName());
|
appAuthRequest.setAppName(config.getAppName());
|
||||||
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
appAuthRequest.setEncryptedPassword(DigestUtils.md5(config.getPassword()));
|
||||||
|
appAuthRequest.setEncryptType(EncryptType.MD5.getCode());
|
||||||
return appAuthRequest;
|
return appAuthRequest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,6 @@ public class ClientInitializer {
|
|||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void initClient() throws Exception {
|
public static void initClient() throws Exception {
|
||||||
powerJobClient = new PowerJobClient("127.0.0.1:7700", "powerjob-worker-samples", "powerjob123");
|
powerJobClient = new PowerJobClient("127.0.0.1:7700", "powerjob-worker-samples", "powerjob12345");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package tech.powerjob.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密类型
|
||||||
|
*
|
||||||
|
* @author tjq
|
||||||
|
* @since 2024/8/10
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum EncryptType {
|
||||||
|
|
||||||
|
NONE("none"),
|
||||||
|
|
||||||
|
MD5("md5")
|
||||||
|
;
|
||||||
|
|
||||||
|
private final String code;
|
||||||
|
}
|
@ -43,7 +43,6 @@ public enum ErrorCodes {
|
|||||||
/**
|
/**
|
||||||
* OPENAPI 错误码号段 -10XX
|
* OPENAPI 错误码号段 -10XX
|
||||||
*/
|
*/
|
||||||
OPEN_API_PASSWORD_ERROR("-1001", "OPEN_API_PASSWORD_ERROR"),
|
|
||||||
OPEN_API_AUTH_FAILED("-1002", "OPEN_API_AUTH_FAILED"),
|
OPEN_API_AUTH_FAILED("-1002", "OPEN_API_AUTH_FAILED"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package tech.powerjob.server.common.utils;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
public class AESUtil {
|
||||||
|
|
||||||
|
// 加密算法的名称
|
||||||
|
private static final String ALGORITHM = "AES";
|
||||||
|
// 加密/解密模式和填充方式
|
||||||
|
private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
|
||||||
|
// 密钥长度(128、192 或 256 位)
|
||||||
|
private static final int KEY_SIZE = 128;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成密钥
|
||||||
|
*
|
||||||
|
* @param key 密钥的种子,可以是任意字符串
|
||||||
|
* @return 生成的密钥
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
private static SecretKeySpec generateKey(String key) throws Exception {
|
||||||
|
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
|
||||||
|
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
secureRandom.setSeed(key.getBytes());
|
||||||
|
keyGen.init(KEY_SIZE, secureRandom);
|
||||||
|
SecretKey secretKey = keyGen.generateKey();
|
||||||
|
return new SecretKeySpec(secretKey.getEncoded(), ALGORITHM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param data 要加密的数据
|
||||||
|
* @param key 密钥
|
||||||
|
* @return 加密后的数据(Base64 编码)
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static String encrypt(String data, String key) {
|
||||||
|
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
SecretKeySpec secretKey = generateKey(key);
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Base64.getEncoder().encodeToString(encryptedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
*
|
||||||
|
* @param encryptedData 要解密的数据(Base64 编码)
|
||||||
|
* @param key 密钥
|
||||||
|
* @return 解密后的数据
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public static String decrypt(String encryptedData, String key) {
|
||||||
|
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
|
||||||
|
SecretKeySpec secretKey = generateKey(key);
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||||
|
byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
|
||||||
|
return new String(decryptedData, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package tech.powerjob.server.common.utils;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AESUtilTest
|
||||||
|
*
|
||||||
|
* @author tjq
|
||||||
|
* @since 2024/8/10
|
||||||
|
*/
|
||||||
|
class AESUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testAes() throws Exception {
|
||||||
|
|
||||||
|
String sk = "cmxzjzty";
|
||||||
|
|
||||||
|
String txt = "kyksjdfh";
|
||||||
|
|
||||||
|
String encrypt = AESUtil.encrypt(txt, sk);
|
||||||
|
System.out.println(encrypt);
|
||||||
|
String decrypt = AESUtil.decrypt(encrypt, sk);
|
||||||
|
System.out.println(decrypt);
|
||||||
|
|
||||||
|
assert txt.equals(decrypt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -12,20 +12,35 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public interface AppInfoService {
|
public interface AppInfoService {
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证 APP 账号密码
|
|
||||||
* @param appName 账号
|
|
||||||
* @param password 原文密码
|
|
||||||
* @return AppId
|
|
||||||
*/
|
|
||||||
Long assertApp(String appName, String password);
|
|
||||||
|
|
||||||
Optional<AppInfoDO> findByAppName(String appName);
|
Optional<AppInfoDO> findByAppName(String appName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 AppInfo(带缓存)
|
* 获取 AppInfo(带缓存)
|
||||||
* @param appId appId
|
* @param appId appId
|
||||||
|
* @param useCache cache
|
||||||
* @return App 信息
|
* @return App 信息
|
||||||
*/
|
*/
|
||||||
Optional<AppInfoDO> findByIdWithCache(Long appId);
|
Optional<AppInfoDO> findById(Long appId, boolean useCache);
|
||||||
|
|
||||||
|
void deleteById(Long appId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存 App
|
||||||
|
* @param appInfo app 信息
|
||||||
|
* @return 保存后结果
|
||||||
|
*/
|
||||||
|
AppInfoDO save(AppInfoDO appInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param appName 验证 APP 账号密码
|
||||||
|
* @param password 密码
|
||||||
|
* @param encryptType 密码类型
|
||||||
|
* @return appId
|
||||||
|
*/
|
||||||
|
Long assertApp(String appName, String password, String encryptType);
|
||||||
|
|
||||||
|
Long assertApp(AppInfoDO appInfo, String password, String encryptType);
|
||||||
|
|
||||||
|
String fetchOriginAppPassword(AppInfoDO appInfo);
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,17 @@ import com.google.common.cache.Cache;
|
|||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.powerjob.common.enums.EncryptType;
|
||||||
|
import tech.powerjob.common.enums.ErrorCodes;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
|
import tech.powerjob.common.utils.DigestUtils;
|
||||||
|
import tech.powerjob.server.common.utils.AESUtil;
|
||||||
import tech.powerjob.server.core.service.AppInfoService;
|
import tech.powerjob.server.core.service.AppInfoService;
|
||||||
import tech.powerjob.server.persistence.remote.model.AppInfoDO;
|
import tech.powerjob.server.persistence.remote.model.AppInfoDO;
|
||||||
import tech.powerjob.server.persistence.remote.repository.AppInfoRepository;
|
import tech.powerjob.server.persistence.remote.repository.AppInfoRepository;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@ -33,21 +37,9 @@ public class AppInfoServiceImpl implements AppInfoService {
|
|||||||
|
|
||||||
private final AppInfoRepository appInfoRepository;
|
private final AppInfoRepository appInfoRepository;
|
||||||
|
|
||||||
/**
|
private static final String ENCRYPT_KEY = "ChinaNo.1";
|
||||||
* 验证应用访问权限
|
|
||||||
* @param appName 应用名称
|
|
||||||
* @param password 密码
|
|
||||||
* @return 应用ID
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Long assertApp(String appName, String password) {
|
|
||||||
|
|
||||||
AppInfoDO appInfo = appInfoRepository.findByAppName(appName).orElseThrow(() -> new PowerJobException("can't find appInfo by appName: " + appName));
|
private static final String ENCRYPT_PWD_PREFIX = "aes:";
|
||||||
if (Objects.equals(appInfo.getPassword(), password)) {
|
|
||||||
return appInfo.getId();
|
|
||||||
}
|
|
||||||
throw new PowerJobException("password error!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<AppInfoDO> findByAppName(String appName) {
|
public Optional<AppInfoDO> findByAppName(String appName) {
|
||||||
@ -55,7 +47,10 @@ public class AppInfoServiceImpl implements AppInfoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<AppInfoDO> findByIdWithCache(Long appId) {
|
public Optional<AppInfoDO> findById(Long appId, boolean useCache) {
|
||||||
|
if (!useCache) {
|
||||||
|
return appInfoRepository.findById(appId);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
AppInfoDO appInfoDO = appId2AppInfoDO.get(appId, () -> {
|
AppInfoDO appInfoDO = appId2AppInfoDO.get(appId, () -> {
|
||||||
Optional<AppInfoDO> appInfoOpt = appInfoRepository.findById(appId);
|
Optional<AppInfoDO> appInfoOpt = appInfoRepository.findById(appId);
|
||||||
@ -71,4 +66,61 @@ public class AppInfoServiceImpl implements AppInfoService {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteById(Long appId) {
|
||||||
|
appInfoRepository.deleteById(appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppInfoDO save(AppInfoDO appInfo) {
|
||||||
|
|
||||||
|
String originPassword = appInfo.getPassword();
|
||||||
|
String encryptPassword = AESUtil.encrypt(originPassword, ENCRYPT_KEY);
|
||||||
|
String finalPassword = ENCRYPT_PWD_PREFIX.concat(encryptPassword);
|
||||||
|
appInfo.setPassword(finalPassword);
|
||||||
|
|
||||||
|
return appInfoRepository.saveAndFlush(appInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long assertApp(String appName, String password, String encryptType) {
|
||||||
|
AppInfoDO appInfo = appInfoRepository.findByAppName(appName).orElseThrow(() -> new PowerJobException(ErrorCodes.INVALID_APP, appName));
|
||||||
|
return assertApp(appInfo, password, encryptType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long assertApp(AppInfoDO appInfo, String password, String encryptType) {
|
||||||
|
boolean checkPass = checkPassword(appInfo, password, encryptType);
|
||||||
|
if (!checkPass) {
|
||||||
|
throw new PowerJobException(ErrorCodes.INCORRECT_PASSWORD, null);
|
||||||
|
}
|
||||||
|
return appInfo.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkPassword(AppInfoDO appInfo, String password, String encryptType) {
|
||||||
|
String originPwd = fetchOriginAppPassword(appInfo);
|
||||||
|
if (StringUtils.isEmpty(encryptType) || EncryptType.NONE.getCode().equalsIgnoreCase(encryptType)) {
|
||||||
|
return password.equals(originPwd);
|
||||||
|
}
|
||||||
|
if (EncryptType.MD5.getCode().equalsIgnoreCase(encryptType)) {
|
||||||
|
return password.equalsIgnoreCase(DigestUtils.md5(originPwd));
|
||||||
|
}
|
||||||
|
throw new PowerJobException(ErrorCodes.INVALID_REQUEST, "unknown_encryptType:" + encryptType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String fetchOriginAppPassword(AppInfoDO appInfo) {
|
||||||
|
String dbPwd = appInfo.getPassword();
|
||||||
|
if (StringUtils.isEmpty(dbPwd)) {
|
||||||
|
return dbPwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbPwd.startsWith(ENCRYPT_PWD_PREFIX)) {
|
||||||
|
String encryptPassword = dbPwd.replaceFirst(ENCRYPT_PWD_PREFIX, StringUtils.EMPTY);
|
||||||
|
return AESUtil.decrypt(encryptPassword, ENCRYPT_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbPwd;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class OpenAPIController {
|
|||||||
|
|
||||||
@PostMapping(OpenAPIConstant.ASSERT)
|
@PostMapping(OpenAPIConstant.ASSERT)
|
||||||
public ResultDTO<Long> assertAppName(String appName, @RequestParam(required = false) String password) {
|
public ResultDTO<Long> assertAppName(String appName, @RequestParam(required = false) String password) {
|
||||||
return ResultDTO.success(appInfoService.assertApp(appName, password));
|
return ResultDTO.success(appInfoService.assertApp(appName, password, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,10 +8,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import tech.powerjob.client.module.AppAuthRequest;
|
import tech.powerjob.client.module.AppAuthRequest;
|
||||||
import tech.powerjob.client.module.AppAuthResult;
|
import tech.powerjob.client.module.AppAuthResult;
|
||||||
import tech.powerjob.common.OpenAPIConstant;
|
import tech.powerjob.common.OpenAPIConstant;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
|
||||||
import tech.powerjob.common.utils.DigestUtils;
|
|
||||||
import tech.powerjob.common.enums.ErrorCodes;
|
import tech.powerjob.common.enums.ErrorCodes;
|
||||||
import tech.powerjob.server.auth.common.PowerJobAuthException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
import tech.powerjob.server.auth.common.utils.HttpServletUtils;
|
import tech.powerjob.server.auth.common.utils.HttpServletUtils;
|
||||||
import tech.powerjob.server.auth.jwt.JwtService;
|
import tech.powerjob.server.auth.jwt.JwtService;
|
||||||
import tech.powerjob.server.core.service.AppInfoService;
|
import tech.powerjob.server.core.service.AppInfoService;
|
||||||
@ -20,7 +18,6 @@ import tech.powerjob.server.persistence.remote.model.AppInfoDO;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,6 +37,7 @@ public class OpenApiSecurityServiceImpl implements OpenApiSecurityService {
|
|||||||
|
|
||||||
private static final String JWT_KEY_APP_ID = "appId";
|
private static final String JWT_KEY_APP_ID = "appId";
|
||||||
private static final String JWT_KEY_APP_PASSWORD = "password";
|
private static final String JWT_KEY_APP_PASSWORD = "password";
|
||||||
|
private static final String JWT_KEY_ENCRYPT_TYPE = "encryptType";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void authAppByToken(HttpServletRequest httpServletRequest) {
|
public void authAppByToken(HttpServletRequest httpServletRequest) {
|
||||||
@ -59,6 +57,7 @@ public class OpenApiSecurityServiceImpl implements OpenApiSecurityService {
|
|||||||
|
|
||||||
Long appIdFromJwt = MapUtils.getLong(jwtResult, JWT_KEY_APP_ID);
|
Long appIdFromJwt = MapUtils.getLong(jwtResult, JWT_KEY_APP_ID);
|
||||||
String passwordFromJwt = MapUtils.getString(jwtResult, JWT_KEY_APP_PASSWORD);
|
String passwordFromJwt = MapUtils.getString(jwtResult, JWT_KEY_APP_PASSWORD);
|
||||||
|
String encryptType = MapUtils.getString(jwtResult, JWT_KEY_ENCRYPT_TYPE);
|
||||||
|
|
||||||
// 校验 appId 一致性
|
// 校验 appId 一致性
|
||||||
if (!StringUtils.equals(appIdFromHeader, String.valueOf(appIdFromJwt))) {
|
if (!StringUtils.equals(appIdFromHeader, String.valueOf(appIdFromJwt))) {
|
||||||
@ -66,15 +65,12 @@ public class OpenApiSecurityServiceImpl implements OpenApiSecurityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 此处不考虑改密码后的缓存时间,毕竟只要改了密码,一定会报错。换言之 OpenAPI 模式下,密码不可更改
|
// 此处不考虑改密码后的缓存时间,毕竟只要改了密码,一定会报错。换言之 OpenAPI 模式下,密码不可更改
|
||||||
Optional<AppInfoDO> appInfoOpt = appInfoService.findByIdWithCache(appIdFromJwt);
|
Optional<AppInfoDO> appInfoOpt = appInfoService.findById(appIdFromJwt, true);
|
||||||
if (!appInfoOpt.isPresent()) {
|
if (!appInfoOpt.isPresent()) {
|
||||||
throw new PowerJobException(ErrorCodes.INVALID_APP, "can_not_find_app");
|
throw new PowerJobException(ErrorCodes.INVALID_APP, "can_not_find_app");
|
||||||
}
|
}
|
||||||
|
|
||||||
String dbOriginPassword = appInfoOpt.get().getPassword();
|
appInfoService.assertApp(appInfoOpt.get(), passwordFromJwt, encryptType);
|
||||||
if (!StringUtils.equals(passwordFromJwt, DigestUtils.md5(dbOriginPassword))) {
|
|
||||||
throw new PowerJobException(ErrorCodes.OPEN_API_PASSWORD_ERROR, "password_compare_failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -84,25 +80,16 @@ public class OpenApiSecurityServiceImpl implements OpenApiSecurityService {
|
|||||||
String appName = appAuthRequest.getAppName();
|
String appName = appAuthRequest.getAppName();
|
||||||
String encryptedPassword = appAuthRequest.getEncryptedPassword();
|
String encryptedPassword = appAuthRequest.getEncryptedPassword();
|
||||||
|
|
||||||
Optional<AppInfoDO> appInfoOpt = appInfoService.findByAppName(appName);
|
Long appId = appInfoService.assertApp(appName, encryptedPassword, appAuthRequest.getEncryptType());
|
||||||
if (!appInfoOpt.isPresent()) {
|
|
||||||
throw new PowerJobAuthException(ErrorCodes.INVALID_APP);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppInfoDO appInfo = appInfoOpt.get();
|
|
||||||
|
|
||||||
// 密码验证失败
|
|
||||||
if (!Objects.equals(DigestUtils.md5(appInfo.getPassword()), encryptedPassword)) {
|
|
||||||
throw new PowerJobAuthException(ErrorCodes.OPEN_API_PASSWORD_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> jwtBody = Maps.newHashMap();
|
Map<String, Object> jwtBody = Maps.newHashMap();
|
||||||
jwtBody.put(JWT_KEY_APP_ID, appInfo.getId());
|
jwtBody.put(JWT_KEY_APP_ID, appId);
|
||||||
jwtBody.put(JWT_KEY_APP_PASSWORD, encryptedPassword);
|
jwtBody.put(JWT_KEY_APP_PASSWORD, encryptedPassword);
|
||||||
|
jwtBody.put(JWT_KEY_ENCRYPT_TYPE, appAuthRequest.getEncryptType());
|
||||||
|
|
||||||
AppAuthResult appAuthResult = new AppAuthResult();
|
AppAuthResult appAuthResult = new AppAuthResult();
|
||||||
|
|
||||||
appAuthResult.setAppId(appInfo.getId());
|
appAuthResult.setAppId(appId);
|
||||||
appAuthResult.setToken(jwtService.build(jwtBody, null));
|
appAuthResult.setToken(jwtService.build(jwtBody, null));
|
||||||
|
|
||||||
return appAuthResult;
|
return appAuthResult;
|
||||||
|
@ -13,7 +13,10 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import tech.powerjob.common.response.ResultDTO;
|
import tech.powerjob.common.response.ResultDTO;
|
||||||
import tech.powerjob.common.serialize.JsonUtils;
|
import tech.powerjob.common.serialize.JsonUtils;
|
||||||
import tech.powerjob.common.utils.CommonUtils;
|
import tech.powerjob.common.utils.CommonUtils;
|
||||||
@ -22,13 +25,12 @@ import tech.powerjob.server.auth.Permission;
|
|||||||
import tech.powerjob.server.auth.Role;
|
import tech.powerjob.server.auth.Role;
|
||||||
import tech.powerjob.server.auth.RoleScope;
|
import tech.powerjob.server.auth.RoleScope;
|
||||||
import tech.powerjob.server.auth.common.AuthConstants;
|
import tech.powerjob.server.auth.common.AuthConstants;
|
||||||
import tech.powerjob.common.enums.ErrorCodes;
|
|
||||||
import tech.powerjob.server.auth.common.PowerJobAuthException;
|
|
||||||
import tech.powerjob.server.auth.interceptor.ApiPermission;
|
import tech.powerjob.server.auth.interceptor.ApiPermission;
|
||||||
import tech.powerjob.server.auth.plugin.ModifyOrCreateDynamicPermission;
|
import tech.powerjob.server.auth.plugin.ModifyOrCreateDynamicPermission;
|
||||||
import tech.powerjob.server.auth.plugin.SaveAppGrantPermissionPlugin;
|
import tech.powerjob.server.auth.plugin.SaveAppGrantPermissionPlugin;
|
||||||
import tech.powerjob.server.auth.service.WebAuthService;
|
import tech.powerjob.server.auth.service.WebAuthService;
|
||||||
import tech.powerjob.server.common.module.WorkerInfo;
|
import tech.powerjob.server.common.module.WorkerInfo;
|
||||||
|
import tech.powerjob.server.core.service.AppInfoService;
|
||||||
import tech.powerjob.server.persistence.PageResult;
|
import tech.powerjob.server.persistence.PageResult;
|
||||||
import tech.powerjob.server.persistence.QueryConvertUtils;
|
import tech.powerjob.server.persistence.QueryConvertUtils;
|
||||||
import tech.powerjob.server.persistence.remote.model.AppInfoDO;
|
import tech.powerjob.server.persistence.remote.model.AppInfoDO;
|
||||||
@ -67,6 +69,7 @@ public class AppInfoController {
|
|||||||
|
|
||||||
private final UserWebService userWebService;
|
private final UserWebService userWebService;
|
||||||
|
|
||||||
|
private final AppInfoService appInfoService;
|
||||||
private final AppInfoRepository appInfoRepository;
|
private final AppInfoRepository appInfoRepository;
|
||||||
|
|
||||||
private final NamespaceWebService namespaceWebService;
|
private final NamespaceWebService namespaceWebService;
|
||||||
@ -86,7 +89,7 @@ public class AppInfoController {
|
|||||||
appInfoDO.setGmtCreate(new Date());
|
appInfoDO.setGmtCreate(new Date());
|
||||||
appInfoDO.setCreator(LoginUserHolder.getUserId());
|
appInfoDO.setCreator(LoginUserHolder.getUserId());
|
||||||
} else {
|
} else {
|
||||||
appInfoDO = appInfoRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("can't find appInfo by id:" + id));
|
appInfoDO = appInfoService.findById(id, false).orElseThrow(() -> new IllegalArgumentException("can't find appInfo by id:" + id));
|
||||||
|
|
||||||
// 不允许修改 appName
|
// 不允许修改 appName
|
||||||
if (!appInfoDO.getAppName().equalsIgnoreCase(req.getAppName())) {
|
if (!appInfoDO.getAppName().equalsIgnoreCase(req.getAppName())) {
|
||||||
@ -104,7 +107,7 @@ public class AppInfoController {
|
|||||||
appInfoDO.setGmtModified(new Date());
|
appInfoDO.setGmtModified(new Date());
|
||||||
appInfoDO.setModifier(LoginUserHolder.getUserId());
|
appInfoDO.setModifier(LoginUserHolder.getUserId());
|
||||||
|
|
||||||
AppInfoDO savedAppInfo = appInfoRepository.saveAndFlush(appInfoDO);
|
AppInfoDO savedAppInfo = appInfoService.save(appInfoDO);
|
||||||
|
|
||||||
// 重现授权
|
// 重现授权
|
||||||
webAuthService.processPermissionOnSave(RoleScope.APP, savedAppInfo.getId(), req.getComponentUserRoleInfo());
|
webAuthService.processPermissionOnSave(RoleScope.APP, savedAppInfo.getId(), req.getComponentUserRoleInfo());
|
||||||
@ -123,7 +126,7 @@ public class AppInfoController {
|
|||||||
return ResultDTO.failed("Unable to delete apps with live workers, Please remove the worker dependency first!");
|
return ResultDTO.failed("Unable to delete apps with live workers, Please remove the worker dependency first!");
|
||||||
}
|
}
|
||||||
|
|
||||||
appInfoRepository.deleteById(appId);
|
appInfoService.deleteById(appId);
|
||||||
log.warn("[AppInfoController] delete app[id={}] successfully!", appId);
|
log.warn("[AppInfoController] delete app[id={}] successfully!", appId);
|
||||||
return ResultDTO.success(null);
|
return ResultDTO.success(null);
|
||||||
}
|
}
|
||||||
@ -188,18 +191,13 @@ public class AppInfoController {
|
|||||||
@ApiPermission(name = "App-BecomeAdmin", roleScope = RoleScope.GLOBAL, requiredPermission = Permission.NONE)
|
@ApiPermission(name = "App-BecomeAdmin", roleScope = RoleScope.GLOBAL, requiredPermission = Permission.NONE)
|
||||||
public ResultDTO<Void> becomeAdminByAppNameAndPassword(@RequestBody AppAssertRequest appAssertRequest) {
|
public ResultDTO<Void> becomeAdminByAppNameAndPassword(@RequestBody AppAssertRequest appAssertRequest) {
|
||||||
String appName = appAssertRequest.getAppName();
|
String appName = appAssertRequest.getAppName();
|
||||||
Optional<AppInfoDO> appInfoOpt = appInfoRepository.findByAppName(appName);
|
|
||||||
if (!appInfoOpt.isPresent()) {
|
Long appId = appInfoService.assertApp(appName, appAssertRequest.getPassword(), appAssertRequest.getEncryptType());
|
||||||
throw new IllegalArgumentException("can't find app by appName: " + appName);
|
|
||||||
}
|
|
||||||
if (!StringUtils.equals(appInfoOpt.get().getPassword(), appAssertRequest.getPassword())) {
|
|
||||||
throw new PowerJobAuthException(ErrorCodes.INCORRECT_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> extra = Maps.newHashMap();
|
Map<String, Object> extra = Maps.newHashMap();
|
||||||
extra.put("source", "becomeAdminByAppNameAndPassword");
|
extra.put("source", "becomeAdminByAppNameAndPassword");
|
||||||
|
|
||||||
webAuthService.grantRole2LoginUser(RoleScope.APP, appInfoOpt.get().getId(), Role.ADMIN, JsonUtils.toJSONString(extra));
|
webAuthService.grantRole2LoginUser(RoleScope.APP, appId, Role.ADMIN, JsonUtils.toJSONString(extra));
|
||||||
|
|
||||||
return ResultDTO.success(null);
|
return ResultDTO.success(null);
|
||||||
}
|
}
|
||||||
@ -224,7 +222,8 @@ public class AppInfoController {
|
|||||||
|
|
||||||
// 密码
|
// 密码
|
||||||
boolean hasPermission = webAuthService.hasPermission(RoleScope.APP, appInfoDO.getId(), Permission.READ);
|
boolean hasPermission = webAuthService.hasPermission(RoleScope.APP, appInfoDO.getId(), Permission.READ);
|
||||||
appInfoVO.setPassword(hasPermission ? appInfoDO.getPassword() : AuthConstants.TIPS_NO_PERMISSION_TO_SEE);
|
String originPassword = appInfoService.fetchOriginAppPassword(appInfoDO);
|
||||||
|
appInfoVO.setPassword(hasPermission ? originPassword : AuthConstants.TIPS_NO_PERMISSION_TO_SEE);
|
||||||
|
|
||||||
// namespace
|
// namespace
|
||||||
Optional<NamespaceDO> namespaceOpt = namespaceWebService.findById(appInfoDO.getNamespaceId());
|
Optional<NamespaceDO> namespaceOpt = namespaceWebService.findById(appInfoDO.getNamespaceId());
|
||||||
|
@ -12,4 +12,6 @@ import lombok.Data;
|
|||||||
public class AppAssertRequest {
|
public class AppAssertRequest {
|
||||||
private String appName;
|
private String appName;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
private String encryptType;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user