接口RSA2验签
由于没有找到网上比较全的资料,所以自己就找资料总结了一下,可以供大家参考,当然,这个写的比较简单,这个可以自己根据业务去修改,希望最大家有帮助
一、自定义注解
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Encryption {
}
二、AOP
@Slf4j
@Aspect
@Component
public class EncryptionAspect {
@Pointcut("@annotation(com.fly.springbootmybatis.annotation.Encryption)")
public void encryption() {
}
@Before("encryption()")
public void LogPrintln(JoinPoint point) throws JsonProcessingException {
Object[] args = point.getArgs();
ApiBaseRequest arg = (ApiBaseRequest) args[0];
String sign = arg.getSign();
String body = arg.getBiz_content();
if (StringUtils.isNotBlank(sign) && StringUtils.isNotBlank(body)) {
boolean isSign = RSA2Utils.verify256(body.getBytes(StandardCharsets.UTF_8),sign, SystemUtils.API_RSA2_SIGN_PUBLIC_KEY);
if (!isSign) {
throw new ApiException(ResultEnum.SIGN_ERROR);
}
} else {
throw new ApiException(ResultEnum.SIGN_ERROR);
}
}
}
三、通用参数实体类
@Data
public class ApiBaseRequest implements Serializable {
private static final long serialVersionUID = 1L;
@NotBlank(message = "请求ID不能为空")
private String appId;
private String format;
private String charset;
private String version = "1.0";
@NotBlank(message = "签名不能为空")
private String sign;
@NotBlank(message = "时间戳不能为空")
private String timestamp;
@NotBlank(message = "请求参数不能为空")
private String biz_content;
}
四、全局异常拦截
/**
* 全局处理异常类
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理业务异常
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = BusinessException.class)
public AjaxResult businessExceptionHandler(BusinessException e) {
log.error(e.getMessage());
return AjaxResult.error(e.getCode(),e.getMessage());
}
/**
* 处理接口异常
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = ApiException.class)
public AjaxResult ApiExceptionHandler(ApiException e) {
log.error(e.getMessage());
return AjaxResult.error(e.getCode(),e.getMessage());
}
@ResponseBody
@ExceptionHandler(value = FileException.class)
public AjaxResult fileExceptionHandler(FileException e) {
log.error(e.getMessage());
return AjaxResult.error(e.getCode(),e.getMessage());
}
/**
* 请求方式不支持
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
public AjaxResult handleException(HttpRequestMethodNotSupportedException e) {
log.error(e.getMessage());
return AjaxResult.error(ResultEnum.NOT_REQUEST_METHOD);
}
/**
* 处理JSR303验证异常
*
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class, ValidateException.class})
public AjaxResult handleVaildException(Exception e) {
BindingResult bindingResult = null;
if (e instanceof MethodArgumentNotValidException) {
bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
} else if (e instanceof BindException) {
bindingResult = ((BindException) e).getBindingResult();
} else if (e instanceof ValidateException) {
return AjaxResult.error(((ValidateException) e).getCode(),e.getMessage(),((ValidateException) e).getData());
}
Map<String, String> errorMap = new HashMap<>(16);
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
fieldErrors.forEach(error -> errorMap.put(error.getField(), error.getDefaultMessage()));
log.info("------参数校验失败:{}", errorMap);
return AjaxResult.error(ResultEnum.ILLEGAL_PARAMETER.getCode(),ResultEnum.ILLEGAL_PARAMETER.getMsg(),errorMap);
}
/**
* 处理上传文件过大异常
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = MaxUploadSizeExceededException.class)
public AjaxResult fileSizeExceededException(MaxUploadSizeExceededException e){
log.error(e.getMessage());
return AjaxResult.error(ResultEnum.FILE_MAX_LIMIT);
}
/**
* 处理其他异常
*
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
public ModelAndView exceptionHandler(Exception e) {
log.error(e.getMessage());
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("5xx");
return modelAndView;
}
}
五、RSA2加密工具类
@Slf4j
public class RSA2Utils {
// 算法类别
private final static String SIGN_TYPE = "RSA";
// 算法位数
private final static Integer KEY_SIZE = 2048;
private RSA2Utils(){};
/**
* 生成公私钥
*/
public static Map<String, String> getPublicPrivateKey() {
Map<String, String> pubPriKey = new HashMap<>();
KeyPair keyPair = KeyUtil.generateKeyPair(SIGN_TYPE, KEY_SIZE);
String publicKeyStr = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
String privateKeyStr = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
pubPriKey.put("publicKey", publicKeyStr);
pubPriKey.put("privateKey", privateKeyStr);
return pubPriKey;
}
/**
* 实例化公钥
*/
public static PublicKey getPublicKey(String publicKey) throws Exception {
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes());
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE);
return keyFactory.generatePublic(keySpec);
}
/**
* 实例化私钥
*/
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey.getBytes());
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE);
return keyFactory.generatePrivate(keySpec);
}
/**
* 签名
*/
public static String sign256(byte[] signData, String priKey) {
try {
byte[] keyBytes = Base64.getDecoder().decode(priKey);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Signature si = Signature.getInstance(SignAlgorithm.SHA256withRSA.getValue());
si.initSign(privateKey);
si.update(signData);
byte[] sign = si.sign();
return Base64.getEncoder().encodeToString(sign);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}
/**
* 验签
*/
public static boolean verify256(byte[] dataBytes, String sign, String pubkey) {
boolean flag = false;
try {
byte[] signByte = Base64.getDecoder().decode(sign);
byte[] encodedKey = Base64.getDecoder().decode(pubkey);
Signature verf = Signature.getInstance(SignAlgorithm.SHA256withRSA.getValue());
KeyFactory keyFac = KeyFactory.getInstance(SIGN_TYPE);
PublicKey puk = keyFac.generatePublic(new X509EncodedKeySpec(encodedKey));
verf.initVerify(puk);
verf.update(dataBytes);
flag = verf.verify(signByte);
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return flag;
}
/**
* RSA2公钥加密
*/
public static byte[] encyptByPublickey(byte[] data, String pubkey) throws Exception {
Cipher cipher = Cipher.getInstance(SIGN_TYPE);
cipher.init(Cipher.ENCRYPT_MODE,getPublicKey(pubkey));
return cipher.doFinal(data);
}
/**
* RSA2私钥解密
*/
public static byte[] decryptByPrivateKey(byte[] content, String privateKey) throws Exception {
Cipher cipher = Cipher.getInstance(SIGN_TYPE);
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(privateKey));
return cipher.doFinal(content);
}
}
六、其他类
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum ResultEnum {
// 数据操作错误定义
NO_PERMISSION(403, "权限不足"),
NO_AUTH(401, "未登录"),
NOT_FOUND(404, "未找到该资源"),
NOT_REQUEST_METHOD(405,"该请求方式不支持"),
INTERNAL_SERVER_ERROR(500, "服务器异常请联系管理员"),
SUCCESS(20000, "成功"),
FAIL(10000,"失败"),
FILE_MAX_LIMIT(10001,"单个文件上传不超过10MB,多个文件上传不超过100MB"),
ILLEGAL_PARAMETER(10002,"非法参数"),
CONVERSION_ERROR(10003,"参数转换错误"),
FILE_READ_ERROR(10004,"文件读取失败"),
SIGN_ERROR(10006,"验签失败"),
REQUEST_ERROR(10007,"请求失效"),
FREQUENT_REQUEST(10008,"请求过于频繁,请稍后再试");
/**
* 错误码
*/
private Integer code;
/**
* 错误信息
*/
private String msg;
}
public class ApiException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 状态码
*/
private Integer code;
/**
* 错误提示
*/
private String message;
public ApiException() {
}
public ApiException(String message) {
this.message = message;
}
public ApiException(Integer code, String message) {
this.code = code;
this.message = message;
}
public ApiException(ResultEnum resultEnum) {
this.code = resultEnum.getCode();
this.message = resultEnum.getMsg();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}