RSA接口加密封装优化

v1.4.1
Parker 4 years ago
parent 9885b962ea
commit 182e1ce709

@ -0,0 +1,28 @@
package org.opsli.api.base.encrypt;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
*
*
* @author
* @date 2021-01-24 12:48
**/
@Data
public class BaseEncrypt implements Serializable {
private static final long serialVersionUID = 1L;
/** 加密数据 */
@ApiModelProperty(value = "加密数据")
@ExcelIgnore
@TableField(exist = false)
private String encryptData;
}

@ -28,6 +28,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.opsli.api.base.encrypt.BaseEncrypt;
import org.opsli.plugins.excel.annotation.ExcelInfo;
import org.springframework.format.annotation.DateTimeFormat;
@ -57,7 +58,7 @@ import java.util.Date;
@HeadFontStyle(fontName = "Arial",color = 9,fontHeightInPoints = 10)
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 23)
@ColumnWidth(22)
public abstract class ApiWrapper implements Serializable {
public abstract class ApiWrapper extends BaseEncrypt implements Serializable {
private static final long serialVersionUID = 1L;

@ -0,0 +1,24 @@
package org.opsli.common.annotation;
import java.lang.annotation.*;
/**
*
* @author Parker
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface InterfaceEncryptAndDecrypt {
/** 加密启用状态 */
boolean enable() default true;
/** 请求解密 */
boolean requestDecrypt() default true;
/** 返回加密 */
boolean responseEncrypt() default true;
}

@ -31,6 +31,9 @@ public interface OrderConstants {
/** token */
int TOKEN_AOP_SORT = 150;
/** 请求加解密 */
int ENCRYPT_ADN_DECRYPT_AOP_SORT = 160;
/** 热点数据加载顺序 */
int HOT_DATA_ORDER = 180;

@ -119,12 +119,10 @@ public final class RateLimiterUtil {
RateLimiterInner rateLimiterInner = rateLimiterInnerMap.get(resource);
// 如果为空 则创建一个新的限流器
if(rateLimiterInner == null){
System.out.println(456);
rateLimiterInner = new RateLimiterInner();
rateLimiterInner.setQps(dfQps);
rateLimiterInner.setRateLimiter(RateLimiter.create(dfQps));
rateLimiterInnerMap.put(resource, rateLimiterInner);
}else{
qps = rateLimiterInner.getQps();
}

@ -0,0 +1,168 @@
/**
* Copyright 2020 OPSLI https://www.opsli.com
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.opsli.core.aspect;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.crypto.asymmetric.RSA;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.opsli.api.base.encrypt.BaseEncrypt;
import org.opsli.api.base.result.ResultVo;
import org.opsli.common.annotation.InterfaceEncryptAndDecrypt;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.Props;
import org.opsli.core.msg.CoreMsg;
import org.opsli.core.utils.EncryptAndDecryptByRsaUtil;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import static org.opsli.common.constants.OrderConstants.ENCRYPT_ADN_DECRYPT_AOP_SORT;
/**
*
*
* @author parker
* @date 2021-01-23
*/
@Slf4j
@Order(ENCRYPT_ADN_DECRYPT_AOP_SORT)
@Aspect
@Component
public class InterfaceEncryptAndDecryptAop {
/** RSA 公钥 */
private static String RSA_PUBLIC_KEY;
/** RSA 私钥 */
private static String RSA_PRIVATE_KEY;
/** RSA */
private static RSA ASSIGN_RSA;
static {
// 缓存前缀
Props props = new Props("application.yaml");
RSA_PUBLIC_KEY = props.getStr("opsli.encrypt-decrypt.rsa.public-key");
RSA_PRIVATE_KEY = props.getStr("opsli.encrypt-decrypt.rsa.private-key");
try {
ASSIGN_RSA = EncryptAndDecryptByRsaUtil.INSTANCE.createRsa(RSA_PUBLIC_KEY, RSA_PRIVATE_KEY);
}catch (Exception e){
ASSIGN_RSA = EncryptAndDecryptByRsaUtil.INSTANCE.createRsa();
RSA_PUBLIC_KEY = ASSIGN_RSA.getPublicKeyBase64();
RSA_PRIVATE_KEY = ASSIGN_RSA.getPrivateKeyBase64();
String errorMsg = StrUtil.format(CoreMsg.OTHER_EXCEPTION_RSA_CREATE.getMessage(),
RSA_PUBLIC_KEY, RSA_PRIVATE_KEY
);
log.error(errorMsg);
}
}
/**
*
* @return
*/
public static String getRsaPublicKey() {
return RSA_PUBLIC_KEY;
}
/**
*
* @return
*/
public static String getRsaPrivateKey() {
return RSA_PRIVATE_KEY;
}
@Pointcut("@annotation(org.opsli.common.annotation.InterfaceEncryptAndDecrypt)")
public void encryptAndDecrypt() {
}
/**
* post
* @param point
*/
@Around("encryptAndDecrypt()")
public Object encryptAndDecryptHandle(ProceedingJoinPoint point) throws Throwable {
// 获得请求参数
Object[] args = point.getArgs();
// 返回结果
Object returnValue = null;
MethodSignature signature = (MethodSignature) point.getSignature();
// 获得 方法
Method method = signature.getMethod();
// 获得方法注解
InterfaceEncryptAndDecrypt annotation =
method.getAnnotation(InterfaceEncryptAndDecrypt.class);
if(annotation != null){
// 1. 拆解请求数据
// request 解密
if (annotation.enable() && annotation.requestDecrypt()){
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
// 参数校验
if(arg instanceof BaseEncrypt){
// 获得加密数据
BaseEncrypt baseEncrypt = (BaseEncrypt) arg;
String encryptData = baseEncrypt.getEncryptData();
// 解密对象
Object dataToObj = EncryptAndDecryptByRsaUtil.INSTANCE.decryptedDataToObj(ASSIGN_RSA, encryptData);
// 根据方法类型转化对象
Type type = TypeUtil.getParamType(method, i);
args[i] = Convert.convert(type, dataToObj);
}
}
}
// 2. 执行方法
returnValue = point.proceed(args);
// 3. 返回响应数据
// response 加密
if (annotation.enable() && annotation.responseEncrypt()){
try {
// 执行加密过程
if(returnValue instanceof ResultVo){
ResultVo<Object> ret = (ResultVo<Object>) returnValue;
ret.setData(
EncryptAndDecryptByRsaUtil.INSTANCE.encryptedData(
ASSIGN_RSA, ret.getData()
)
);
returnValue = ret;
}else {
returnValue = EncryptAndDecryptByRsaUtil.INSTANCE.encryptedData(
ASSIGN_RSA, returnValue
);
}
}catch (Exception e){
// RSA非对称加密失败
throw new ServiceException(CoreMsg.OTHER_EXCEPTION_RSA_EN);
}
}
}
return returnValue;
}
}

@ -69,9 +69,10 @@ public enum CoreMsg implements BaseMsg {
/** 其他 */
OTHER_EXCEPTION_LIMITER(10700,"当前系统繁忙,请稍后再试"),
OTHER_EXCEPTION_RSA_EN(10701,"RSA非对称加密失败"),
OTHER_EXCEPTION_RSA_DE(10701,"RSA非对称解密失败"),
OTHER_EXCEPTION_RSA_REFLEX(10702,"RSA非对称解密反射失败"),
OTHER_EXCEPTION_RSA_CREATE(10701,"指定RSA算法器创建失败系统已自动创建随机RSA算法\n公钥{}\n私钥{}"),
OTHER_EXCEPTION_RSA_EN(10702,"RSA非对称加密失败"),
OTHER_EXCEPTION_RSA_DE(10703,"RSA非对称解密失败"),
OTHER_EXCEPTION_RSA_REFLEX(10704,"RSA非对称解密反射失败"),
;

@ -22,6 +22,7 @@ import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSONObject;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.Props;
import org.opsli.core.msg.CoreMsg;
import java.util.Collection;
@ -31,10 +32,10 @@ import java.util.Collection;
*
* @author
*/
public enum AsymmetricCryptoUtil {
public enum EncryptAndDecryptByRsaUtil {
/** 实例 */
INSTANCE;
/** 默认实例 */
INSTANCE();
/** RSA KEY */
private final String rsaKey = "data";
@ -42,11 +43,11 @@ public enum AsymmetricCryptoUtil {
/** RSA对象 */
private final RSA rsa;
AsymmetricCryptoUtil(){
// 初始化RSA对象
EncryptAndDecryptByRsaUtil(){
this.rsa = this.createRsa();
}
/**
* RSA
* @return RSA
@ -74,6 +75,14 @@ public enum AsymmetricCryptoUtil {
return rsa.getPublicKeyBase64();
}
/**
*
* @return String
*/
public String getPrivateKey(){
return rsa.getPrivateKeyBase64();
}
/**
* RSA
* @param data

@ -3,8 +3,10 @@ import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import lombok.Data;
import org.junit.Test;
import org.opsli.core.utils.AsymmetricCryptoUtil;
import org.opsli.core.utils.EncryptAndDecryptByRsaUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@ -18,7 +20,7 @@ public class RsaTest {
*/
@Test
public void getPublicKey(){
System.out.println(AsymmetricCryptoUtil.INSTANCE.getPublicKey());
System.out.println(EncryptAndDecryptByRsaUtil.INSTANCE.getPublicKey());
}
@ -36,18 +38,24 @@ public class RsaTest {
// t1.setName( "张三");
// t1.setAge( 16);
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(111);
Object parse = JSONObject.parse("{\"username\":\"demo\",\"password\":\"Aa123456\",\"captcha\":\"\",\"uuid\":\"0d3eea43edf19e4ed0e88aae8d56878046a5\"}");
// 加密
String encryptedData = AsymmetricCryptoUtil.INSTANCE.encryptedData(parse);
String encryptedData = EncryptAndDecryptByRsaUtil.INSTANCE.encryptedData(list);
System.out.println(encryptedData);
// 解密
String decryptedData = AsymmetricCryptoUtil.INSTANCE.decryptedData(encryptedData);
Object decryptedDataToObj = AsymmetricCryptoUtil.INSTANCE.decryptedDataToObj(encryptedData);
String decryptedData = EncryptAndDecryptByRsaUtil.INSTANCE.decryptedData(encryptedData);
Object decryptedDataToObj = EncryptAndDecryptByRsaUtil.INSTANCE.decryptedDataToObj(encryptedData);
System.out.println(decryptedData);
// 解密
List<Integer> integers = Convert.toList(Integer.class, decryptedDataToObj);
//Map<String, Object> stringObjectMap = Convert.toMap(String.class, Object.class, decryptedData);
//Map<String, Object> stringObjectMap = Convert.toMap(String.class, Object.class, decryptedDataToObj);

@ -18,6 +18,7 @@ package org.opsli.modulars.system.login.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.opsli.api.base.encrypt.BaseEncrypt;
import org.opsli.common.annotation.validation.ValidationArgs;
import org.opsli.common.annotation.validation.ValidationArgsLenMax;
import org.opsli.common.annotation.validation.ValidationArgsLenMin;
@ -31,7 +32,7 @@ import org.opsli.common.enums.ValiArgsType;
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class LoginForm {
public class LoginForm extends BaseEncrypt {
/** 用户名 */
@ApiModelProperty(value = "用户名")
@ -52,7 +53,6 @@ public class LoginForm {
/** UUID */
@ApiModelProperty(value = "UUID")
@ValidationArgs(ValiArgsType.IS_NOT_NULL)
private String uuid;
}

@ -15,8 +15,6 @@
*/
package org.opsli.modulars.system.login.web;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@ -26,6 +24,7 @@ import org.opsli.api.base.result.ResultVo;
import org.opsli.api.utils.ValidationUtil;
import org.opsli.api.wrapper.system.tenant.TenantModel;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.InterfaceEncryptAndDecrypt;
import org.opsli.common.annotation.Limiter;
import org.opsli.common.api.TokenThreadLocal;
import org.opsli.common.enums.AlertType;
@ -33,14 +32,13 @@ import org.opsli.common.exception.TokenException;
import org.opsli.common.thread.refuse.AsyncProcessQueueReFuse;
import org.opsli.common.utils.IPUtil;
import org.opsli.common.utils.OutputStreamUtil;
import org.opsli.core.aspect.InterfaceEncryptAndDecryptAop;
import org.opsli.core.msg.TokenMsg;
import org.opsli.core.security.shiro.realm.JwtRealm;
import org.opsli.core.utils.*;
import org.opsli.modulars.system.login.entity.LoginForm;
import org.opsli.modulars.system.login.entity.LoginFormStr;
import org.opsli.modulars.system.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -67,41 +65,18 @@ import java.util.Map;
@RestController
public class LoginRestController {
/** 登录是否开启 RSA加密 */
@Value("${opsli.login.login-rsa:false}")
private boolean loginRsa;
@Autowired
private IUserService iUserService;
/**
*
*/
@Limiter
@InterfaceEncryptAndDecrypt(responseEncrypt = false)
@ApiOperation(value = "登录", notes = "登录")
@PostMapping("/sys/login")
public ResultVo<?> login(@RequestBody LoginFormStr formStr, HttpServletRequest request){
// 非空验证
if(formStr == null || StringUtils.isBlank(formStr.getLoginFormStr())){
throw new TokenException(TokenMsg.EXCEPTION_LOGIN_NULL);
}
LoginForm form;
try{
Object loginFromObj;
if(loginRsa){
loginFromObj = AsymmetricCryptoUtil.INSTANCE.decryptedDataToObj(formStr.getLoginFormStr());
}else {
loginFromObj = JSONObject.parse(formStr.getLoginFormStr());
}
form = Convert.convert(LoginForm.class, loginFromObj);
}catch (Exception e){
log.error("登录账号密码解析失败 - 解析值:["+formStr.getLoginFormStr()+"]",e.getMessage(), e);
// 登录账号密码解析失败
throw new TokenException(TokenMsg.EXCEPTION_LOGIN_DECRYPT);
}
public ResultVo<?> login(@RequestBody LoginForm form, HttpServletRequest request){
// 非空验证
if(form == null){
throw new TokenException(TokenMsg.EXCEPTION_LOGIN_NULL);
@ -110,7 +85,6 @@ public class LoginRestController {
// 验证登录对象
ValidationUtil.verify(form);
// 判断账号是否临时锁定
UserTokenUtil.verifyLockAccount(form.getUsername());
@ -234,7 +208,7 @@ public class LoginRestController {
public ResultVo<?> getPublicKey(){
return ResultVo.success(
"操作成功!",
AsymmetricCryptoUtil.INSTANCE.getPublicKey()
InterfaceEncryptAndDecryptAop.getRsaPublicKey()
);
}

@ -203,6 +203,14 @@ opsli:
# 失败锁定时间(秒)
slip-lock-speed: 300
#加解密
encrypt-decrypt:
# RSA 加密算法
rsa:
# 公钥
public-key: "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCakyyq8rfkmKvKB2fz3hUeuD6tgParCmZmRc1OoL5EN+yXghQmDIrcZhewLZZLUpLQd3T3cRxKaW30nWNfoteNHgKjGYGu4+BZoyHZ8ltTmrolYGopiSwBMhO7kwAD4IK1PZHaoF2wPISH35ubbugykav7dTaWBDuNkvyBiv8qMQIDAQAB"
# 私钥
private-key: "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJqTLKryt+SYq8oHZ/PeFR64Pq2A9qsKZmZFzU6gvkQ37JeCFCYMitxmF7AtlktSktB3dPdxHEppbfSdY1+i140eAqMZga7j4FmjIdnyW1OauiVgaimJLAEyE7uTAAPggrU9kdqgXbA8hIffm5tu6DKRq/t1NpYEO42S/IGK/yoxAgMBAAECgYEAiWu+klwm0LxKPdpHuK7/58e1MVst8PHWB6aW2AhgHxX46NlkQE92RGsfNCnTLDPFAkCxZCrTE/SXJJmn9yY2qoS26OV0PbTGajk96M8lDi9JSmWCNV1eywPecObSyvtPd5jaPtq2jkgNY/hHJjH6kV7UAFZuaSK7jxskfq7uR2ECQQDPfmGjPiMc65+LE9U7jC4LokyUi1yCgN6AY5MgF6fkxUVJD2mtl9BqRK7qE0OnsRb0NzID3PSfa7aA2I0Rlsj/AkEAvrXUBQ6hfuEwD1896qpSJUr7tLidby/3jYwSoewuydDT2duDc2ZCz4/U/1NpxSxWT10ZZi2ExsFZn/3PDylczwJARA3oijkcHSUu69eybVh51bkCswnOasNHtwZxv+niWEdXhTH38EbFxcUHNaDh5MNRiwH7dobm+M7EShg8lJNHEwJAclRdU97OkFr9zeliHCGZd4P5XAFlWHfgJ7p2nR4Teqe3qZ6Aspj2qqpmnd7qxOrsn02H4YqeU+0sBs9I56T7XwJAAg8wHrh/FAPY96mAya0bpv6zm/7bave17vs+8B+fhBEHHuvetfv8Xi/RkXL0rjE4LaTHefoUbZPNbIhNYiN0CQ=="
# Excel 最大操作数量 防止OOM
excel-max-count: 20000

Loading…
Cancel
Save