From a659ff7fa16b1af4aa8cd3611d0edf426457038e Mon Sep 17 00:00:00 2001 From: kaede10 Date: Tue, 12 Mar 2024 10:32:21 +0800 Subject: [PATCH 1/3] Add authentication interceptor --- pom.xml | 6 + .../adapter/MyErrorController.java | 24 -- .../query/ApplicationVersionQueryAdapter.java | 4 + .../common/config/OneidInterceptorConfig.java | 22 ++ .../common/entity/MessageCode.java | 1 + .../common/exception/AuthException.java | 12 + .../exception/GlobalExceptionHandler.java | 21 +- .../common/interceptor/CompatibleToken.java | 12 + .../common/interceptor/OneidInterceptor.java | 305 ++++++++++++++++++ .../common/interceptor/OneidToken.java | 12 + .../easysoftware/common/utils/ApiUtil.java | 2 +- .../common/utils/HttpClientUtil.java | 28 +- .../easysoftware/common/utils/RSAUtil.java | 176 ++++++++++ 13 files changed, 596 insertions(+), 29 deletions(-) delete mode 100644 src/main/java/com/easysoftware/adapter/MyErrorController.java create mode 100644 src/main/java/com/easysoftware/common/config/OneidInterceptorConfig.java create mode 100644 src/main/java/com/easysoftware/common/exception/AuthException.java create mode 100644 src/main/java/com/easysoftware/common/interceptor/CompatibleToken.java create mode 100644 src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java create mode 100644 src/main/java/com/easysoftware/common/interceptor/OneidToken.java create mode 100644 src/main/java/com/easysoftware/common/utils/RSAUtil.java diff --git a/pom.xml b/pom.xml index 169f8ac..f1b66f0 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,12 @@ 4.5.13 + + com.auth0 + java-jwt + 3.4.0 + + diff --git a/src/main/java/com/easysoftware/adapter/MyErrorController.java b/src/main/java/com/easysoftware/adapter/MyErrorController.java deleted file mode 100644 index 26ae043..0000000 --- a/src/main/java/com/easysoftware/adapter/MyErrorController.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.easysoftware.adapter; - -import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import com.easysoftware.common.entity.MessageCode; -import com.easysoftware.common.utils.ResultUtil; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -@RestController -public class MyErrorController implements ErrorController{ - private final String ERROR_PATH = "/error"; - - @RequestMapping(value = ERROR_PATH) - public ResponseEntity errorHtml(HttpServletRequest request, HttpServletResponse response) { - return ResultUtil.fail(HttpStatus.NOT_FOUND, MessageCode.EC0001); - } -} - diff --git a/src/main/java/com/easysoftware/adapter/query/ApplicationVersionQueryAdapter.java b/src/main/java/com/easysoftware/adapter/query/ApplicationVersionQueryAdapter.java index 7529b04..a60d9d2 100644 --- a/src/main/java/com/easysoftware/adapter/query/ApplicationVersionQueryAdapter.java +++ b/src/main/java/com/easysoftware/adapter/query/ApplicationVersionQueryAdapter.java @@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RestController; import com.easysoftware.aop.LimitRequest; import com.easysoftware.application.applicationversion.ApplicationVersionService; import com.easysoftware.application.applicationversion.dto.ApplicationVersionSearchCondition; +import com.easysoftware.common.interceptor.CompatibleToken; +import com.easysoftware.common.interceptor.OneidToken; import jakarta.validation.Valid; @@ -20,6 +22,8 @@ public class ApplicationVersionQueryAdapter { @GetMapping() @LimitRequest() + @OneidToken + @CompatibleToken public ResponseEntity searchAppVersion(@Valid ApplicationVersionSearchCondition condition) { ResponseEntity res = appVersionService.searchAppVersion(condition); return res; diff --git a/src/main/java/com/easysoftware/common/config/OneidInterceptorConfig.java b/src/main/java/com/easysoftware/common/config/OneidInterceptorConfig.java new file mode 100644 index 0000000..f433af0 --- /dev/null +++ b/src/main/java/com/easysoftware/common/config/OneidInterceptorConfig.java @@ -0,0 +1,22 @@ +package com.easysoftware.common.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import com.easysoftware.common.interceptor.OneidInterceptor; + +@Configuration +public class OneidInterceptorConfig implements WebMvcConfigurer { + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(OneidInterceptor()) + .addPathPatterns("/appVersion/**"); + } + + @Bean + public OneidInterceptor OneidInterceptor() { + return new OneidInterceptor(); + } +} diff --git a/src/main/java/com/easysoftware/common/entity/MessageCode.java b/src/main/java/com/easysoftware/common/entity/MessageCode.java index 7120984..44f0330 100644 --- a/src/main/java/com/easysoftware/common/entity/MessageCode.java +++ b/src/main/java/com/easysoftware/common/entity/MessageCode.java @@ -28,6 +28,7 @@ public enum MessageCode { EC0009("EC0009", "Item not existed", "项目不存在"), EC00010("EC00010", "Request exceeds the limit", "请求超过限制"), EC00011("EC00011", "Failed to retrieve field using reflection", "无法通过反射获取字段"), + EC00012("EC00012", "Unauthorized", "身份认证失败"), // self service exception ES0001("ES0001", "Internal Server Error", "服务异常"); diff --git a/src/main/java/com/easysoftware/common/exception/AuthException.java b/src/main/java/com/easysoftware/common/exception/AuthException.java new file mode 100644 index 0000000..07a44c8 --- /dev/null +++ b/src/main/java/com/easysoftware/common/exception/AuthException.java @@ -0,0 +1,12 @@ +package com.easysoftware.common.exception; + +public class AuthException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public AuthException(String message) { + super(message); + } + + public AuthException() { + } +} \ No newline at end of file diff --git a/src/main/java/com/easysoftware/common/exception/GlobalExceptionHandler.java b/src/main/java/com/easysoftware/common/exception/GlobalExceptionHandler.java index b145e2b..1424f2a 100644 --- a/src/main/java/com/easysoftware/common/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/easysoftware/common/exception/GlobalExceptionHandler.java @@ -14,7 +14,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -@RestControllerAdvice() +@RestControllerAdvice public class GlobalExceptionHandler { private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); @@ -38,4 +38,23 @@ public class GlobalExceptionHandler { logger.error(MessageCode.EC0009.getMsgEn()); return ResultUtil.fail(HttpStatus.BAD_REQUEST, MessageCode.EC0009); } + + @ExceptionHandler(AuthException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public ResponseEntity exception(AuthException e) { + logger.error(e.getMessage()); + return ResultUtil.fail(HttpStatus.UNAUTHORIZED, MessageCode.EC00012, e.getMessage()); + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseEntity exception(Exception e) { + return ResultUtil.fail(HttpStatus.INTERNAL_SERVER_ERROR, MessageCode.ES0001); + } + + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ResponseEntity exception(RuntimeException e) { + return ResultUtil.fail(HttpStatus.INTERNAL_SERVER_ERROR, MessageCode.ES0001, e.getMessage()); + } } diff --git a/src/main/java/com/easysoftware/common/interceptor/CompatibleToken.java b/src/main/java/com/easysoftware/common/interceptor/CompatibleToken.java new file mode 100644 index 0000000..c3df690 --- /dev/null +++ b/src/main/java/com/easysoftware/common/interceptor/CompatibleToken.java @@ -0,0 +1,12 @@ +package com.easysoftware.common.interceptor; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CompatibleToken { + boolean required() default true; +} diff --git a/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java new file mode 100644 index 0000000..ed6e1a3 --- /dev/null +++ b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java @@ -0,0 +1,305 @@ +package com.easysoftware.common.interceptor; + +import java.lang.reflect.Method; +import java.security.interfaces.RSAPrivateKey; +import java.util.*; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.easysoftware.common.exception.AuthException; +import com.easysoftware.common.utils.HttpClientUtil; +import com.easysoftware.common.utils.ObjectMapperUtil; +import com.easysoftware.common.utils.RSAUtil; +import com.fasterxml.jackson.databind.JsonNode; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; + +import org.apache.commons.lang3.StringUtils; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.DigestUtils; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class OneidInterceptor implements HandlerInterceptor { + + @Value("${cookie.token.name}") + private String cookieTokenName; + + @Value("${cookie.token.domains}") + private String allowDomains; + + @Value("${cookie.token.secures}") + private String cookieSecures; + + @Value("${oneid.tokenBasePassword}") + private String oneidTokenBasePassword; + + @Value("${oneid.permissionApi}") + private String permissionApi; + + @Value("${rsa.authing.privateKey}") + private String rsaAuthingPrivateKey; + + @Value("${oneid.manage.apiBody}") + private String manageApiBody; + + @Value("${oneid.manage.tokenApi}") + private String manageTokenApi; + + private static final Logger logger = LoggerFactory.getLogger(OneidInterceptor.class); + + @Override + public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, + Object object) throws Exception { + if (!(object instanceof HandlerMethod)) { + return true; + } + + // 检查是否有用户权限的注解 + HandlerMethod handlerMethod = (HandlerMethod) object; + Method method = handlerMethod.getMethod(); + if (!method.isAnnotationPresent(OneidToken.class) && !method.isAnnotationPresent(CompatibleToken.class)) { + return true; + } + OneidToken oneidToken = method.getAnnotation(OneidToken.class); + CompatibleToken compatibleToken = method.getAnnotation(CompatibleToken.class); + if ((oneidToken == null || !oneidToken.required()) + && (compatibleToken == null || !compatibleToken.required())) { + return true; + } + + String headerToken = httpServletRequest.getHeader("token"); + String headJwtTokenMd5 = verifyHeaderToken(headerToken); + if (StringUtils.isBlank(headJwtTokenMd5) || headJwtTokenMd5.equals("unauthorized") ) { + throw new AuthException("unauthorized"); + } + + // 校验domain + String verifyDomainMsg = verifyDomain(httpServletRequest); + if (!verifyDomainMsg.equals("success")) { + throw new AuthException(verifyDomainMsg); + } + + // 校验cookie + Cookie tokenCookie = verifyCookie(httpServletRequest); + if (tokenCookie == null) { + throw new AuthException("unauthorized"); + } + + // 解密cookie中加密的token + String token = tokenCookie.getValue(); + try { + RSAPrivateKey privateKey = RSAUtil.getPrivateKey(rsaAuthingPrivateKey); + token = RSAUtil.privateDecrypt(token, privateKey); + } catch (Exception e) { + throw new AuthException("unauthorized"); + } + + // 解析token + String userId; + Date issuedAt; + Date expiresAt; + String permission; + String verifyToken; + try { + DecodedJWT decode = JWT.decode(token); + userId = decode.getAudience().get(0); + issuedAt = decode.getIssuedAt(); + expiresAt = decode.getExpiresAt(); + String permissionTemp = decode.getClaim("permission").asString(); + permission = new String(Base64.getDecoder().decode(permissionTemp.getBytes())); + verifyToken = decode.getClaim("verifyToken").asString(); + } catch (JWTDecodeException j) { + throw new AuthException("token error"); + } + + // 校验token + String verifyTokenMsg = verifyToken(headJwtTokenMd5, token, verifyToken, userId, issuedAt, expiresAt, + permission); + logger.info(verifyTokenMsg); + if (!verifyTokenMsg.equals("success")) { + throw new AuthException(verifyTokenMsg); + } + + // 校验查看版本兼容页面的权限 + if (compatibleToken != null && compatibleToken.required()) { + String verifyUserMsg = verifyUser(compatibleToken, httpServletRequest, tokenCookie); + if (!verifyUserMsg.equals("success")) { + throw new AuthException(verifyUserMsg); + } + } + + return true; + } + + @Override + public void postHandle(HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, + Object o, ModelAndView modelAndView) throws Exception { + + } + + @Override + public void afterCompletion(HttpServletRequest httpServletRequest, + HttpServletResponse httpServletResponse, + Object o, Exception e) throws Exception { + } + + private String verifyToken(String headerToken, String token, String verifyToken, + String userId, Date issuedAt, Date expiresAt, String permission) { + try { + if (!headerToken.equals(verifyToken)) { + return "unauthorized"; + } + + if (expiresAt.before(new Date())) { + return "token expires"; + } + + // token 签名密码验证 + String password = permission + oneidTokenBasePassword; + JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); + jwtVerifier.verify(token); + + } catch (Exception e) { + return "unauthorized"; + } + return "success"; + } + + /** + * 校验header中的token + * + * @param headerToken header中的token + * @return 校验正确返回token的MD5值 + */ + private String verifyHeaderToken(String headerToken) { + try { + if (StringUtils.isBlank(headerToken)) { + return "unauthorized"; + } + + // token 签名密码验证 + String password = oneidTokenBasePassword; + JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); + jwtVerifier.verify(headerToken); + return DigestUtils.md5DigestAsHex(headerToken.getBytes()); + } catch (Exception e) { + logger.error("verify h eadertoken exception", e); + return "unauthorized"; + } + } + + /** + * 校验用户操作权限 + */ + private String verifyUser(CompatibleToken compatibleToken, HttpServletRequest httpServletRequest, + Cookie tokenCookie) { + try { + if (compatibleToken != null && compatibleToken.required()) { + List pers = getUserPermission(httpServletRequest, tokenCookie); + for (String per : pers) { + if (per.equalsIgnoreCase("easysoftwareread")) { + return "success"; + } + } + } + } catch (Exception e) { + logger.error("verify user exception", e); + throw new RuntimeException(); + } + return "No permission"; + } + + @SneakyThrows + private List getUserPermission(HttpServletRequest httpServletRequest, Cookie tokenCookie) { + String token = getManageToken(); + String userToken = httpServletRequest.getHeader("token"); + String tokenCookieValue = tokenCookie.getValue(); + String response = HttpClientUtil.getHttpClient(permissionApi, token, userToken, tokenCookieValue); + JsonNode res = ObjectMapperUtil.toJsonNode(response); + JsonNode permissions = res.get("data").get("permissions"); + List list = new ArrayList<>(); + for (JsonNode per : permissions) { + list.add(per.asText()); + } + return list; + } + + @SneakyThrows + private String getManageToken() { + String response = HttpClientUtil.postHttpClient(manageTokenApi, manageApiBody); + JsonNode res = ObjectMapperUtil.toJsonNode(response); + return res.get("token").asText(); + } + + /** + * 获取包含存token的cookie + * + * @param httpServletRequest request + * @return cookie + */ + private Cookie verifyCookie(HttpServletRequest httpServletRequest) { + Cookie[] cookies = httpServletRequest.getCookies(); + Cookie cookie = null; + if (cookies != null) { + // 获取cookie中的token + Optional first = Arrays.stream(cookies).filter(c -> cookieTokenName.equals(c.getName())) + .findFirst(); + if (first.isPresent()) + cookie = first.get(); + } + return cookie; + } + + /** + * 校验domain + * + * @param httpServletRequest request + * @return 是否可访问 + */ + private String verifyDomain(HttpServletRequest httpServletRequest) { + String referer = httpServletRequest.getHeader("referer"); + String origin = httpServletRequest.getHeader("origin"); + String[] domains = allowDomains.split(";"); + + boolean checkReferer = checkDomain(domains, referer); + boolean checkOrigin = checkDomain(domains, origin); + + if (!checkReferer && !checkOrigin) { + return "unauthorized"; + } + return "success"; + } + + private boolean checkDomain(String[] domains, String input) { + if (StringUtils.isBlank(input)) + return true; + int fromIndex; + int endIndex; + if (input.startsWith("http://")) { + fromIndex = 7; + endIndex = input.indexOf(":", fromIndex); + } else { + fromIndex = 8; + endIndex = input.indexOf("/", fromIndex); + endIndex = endIndex == -1 ? input.length() : endIndex; + } + String substring = input.substring(0, endIndex); + for (String domain : domains) { + if (substring.endsWith(domain)) + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/easysoftware/common/interceptor/OneidToken.java b/src/main/java/com/easysoftware/common/interceptor/OneidToken.java new file mode 100644 index 0000000..eb58dcc --- /dev/null +++ b/src/main/java/com/easysoftware/common/interceptor/OneidToken.java @@ -0,0 +1,12 @@ +package com.easysoftware.common.interceptor; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface OneidToken { + boolean required() default true; +} diff --git a/src/main/java/com/easysoftware/common/utils/ApiUtil.java b/src/main/java/com/easysoftware/common/utils/ApiUtil.java index 8f8fbfb..afa1157 100644 --- a/src/main/java/com/easysoftware/common/utils/ApiUtil.java +++ b/src/main/java/com/easysoftware/common/utils/ApiUtil.java @@ -9,7 +9,7 @@ public class ApiUtil { public static Map getApiResponse(String url) { Map res = new HashMap<>(); - String response = HttpClientUtil.getHttpClient(url); + String response = HttpClientUtil.getHttpClient(url, null, null, null); if (response != null) { JsonNode info = ObjectMapperUtil.toJsonNode(response); if (info.get("code").asInt() == 200 && !info.get("data").isNull()) { diff --git a/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java b/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java index bba20a6..a3f1aef 100644 --- a/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java +++ b/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java @@ -9,6 +9,8 @@ import java.net.URL; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; @@ -65,16 +67,36 @@ public class HttpClientUtil { return null; } - public static String getHttpClient(String uri) { + public static String getHttpClient(String uri, String token, String userToken, String cookie) { HttpClient httpClient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet(uri); + + if (token != null) httpGet.addHeader("token", token); + if (userToken != null) httpGet.addHeader("user-token", userToken); + if (cookie != null) httpGet.addHeader("Cookie", "_Y_G_=" + cookie); + try { HttpResponse response = httpClient.execute(httpGet); String responseBody = EntityUtils.toString(response.getEntity()); return responseBody; } catch (Exception e) { - logger.error(MessageCode.EC0001.getMsgEn(), e); + throw new RuntimeException(MessageCode.EC0001.getMsgEn()); + } + } + + public static String postHttpClient(String uri, String requestBody) { + HttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(uri); + try { + httpPost.setHeader("Content-Type", "application/json"); + StringEntity stringEntity = new StringEntity(requestBody); + httpPost.setEntity(stringEntity); + HttpResponse response = httpClient.execute(httpPost); + String responseBody = EntityUtils.toString(response.getEntity()); + logger.info("responseBody" + responseBody); + return responseBody; + } catch (Exception e) { + throw new RuntimeException(MessageCode.EC0001.getMsgEn()); } - return null; } } diff --git a/src/main/java/com/easysoftware/common/utils/RSAUtil.java b/src/main/java/com/easysoftware/common/utils/RSAUtil.java new file mode 100644 index 0000000..5eb9905 --- /dev/null +++ b/src/main/java/com/easysoftware/common/utils/RSAUtil.java @@ -0,0 +1,176 @@ +package com.easysoftware.common.utils; + +import java.io.ByteArrayOutputStream; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import org.apache.commons.codec.binary.Base64; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + + +@Component +public class RSAUtil implements Serializable { + public static String KEY_ALGORITHM; + public static String RSA_ALGORITHM; + + @Value("${rsa.key.algorithm:RSA}") + public void setKeyAlgorithm(String keyAlgorithm) { RSAUtil.KEY_ALGORITHM = keyAlgorithm; } + + @Value("${rsa.authing.algorithm}") + public void setRsaAlgorithm(String rsaAlgorithm) { RSAUtil.RSA_ALGORITHM = rsaAlgorithm; } + + /** + * 随机生成密钥对(公钥和私钥) + * + * @param keySize 密钥长度 + */ + public static Map createKeys(int keySize) throws NoSuchAlgorithmException { + //为RSA算法创建一个KeyPairGenerator对象 + KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); + //初始化KeyPairGenerator对象,密钥长度 + kpg.initialize(keySize); + //生成密匙对 + KeyPair keyPair = kpg.generateKeyPair(); + //得到公钥 + Key publicKey = keyPair.getPublic(); + String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); + //得到私钥 + Key privateKey = keyPair.getPrivate(); + String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); + + Map keyPairMap = new HashMap<>(); + keyPairMap.put("publicKey", publicKeyStr); + keyPairMap.put("privateKey", privateKeyStr); + return keyPairMap; + } + + /** + * 获取公钥 + * + * @param publicKey 密钥字符串(经过base64编码) + */ + public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + // 通过X509编码的Key指令获得公钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); + return (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); + } + + /** + * 获取私钥 + * + * @param privateKey 密钥字符串(经过base64编码) + */ + public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { + //通过PKCS#8编码的Key指令获得私钥对象 + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); + return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); + } + + /** + * 公钥加密 + * + * @param data 明文 + * @param publicKey 公钥 + */ + public static String publicEncrypt(String data, RSAPublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, publicKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(StandardCharsets.UTF_8), publicKey.getModulus().bitLength())); + } + + /** + * 私钥解密 + * + * @param data 密文 + * @param privateKey 私钥 + */ + public static String privateDecrypt(String data, RSAPrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), StandardCharsets.UTF_8); + } + + /** + * 私钥加密 + * + * @param data 明文 + * @param privateKey 私钥 + */ + public static String privateEncrypt(String data, RSAPrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, privateKey); + return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(StandardCharsets.UTF_8), privateKey.getModulus().bitLength())); + } + + /** + * 公钥解密 + * + * @param data 密文 + * @param publicKey 公钥 + */ + public static String publicDecrypt(String data, RSAPublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { + Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, publicKey); + return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), StandardCharsets.UTF_8); + } + + /** + * 对数据分段加密码、解密 + * + * @param cipher 密码服务 + * @param opmode 加密 or 解密 + * @param datas 需要加密或者解密的内容 + * @param keySize 密钥长度 + */ + private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) { + int maxBlock = 0; + if (opmode == Cipher.DECRYPT_MODE) { + maxBlock = keySize / 8; + } else { + maxBlock = keySize / 8 - 2 * 32 - 2; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] buff; + int i = 0; + try { + while (datas.length > offSet) { + if (datas.length - offSet > maxBlock) { + buff = cipher.doFinal(datas, offSet, maxBlock); + } else { + buff = cipher.doFinal(datas, offSet, datas.length - offSet); + } + out.write(buff, 0, buff.length); + i++; + offSet = i * maxBlock; + } + } catch (Exception e) { + throw new RuntimeException("Cipher Mode: " + opmode + " Error", e); + } + byte[] dataResult = out.toByteArray(); + IOUtils.closeQuietly(out); + return dataResult; + } + + public static void main(String[] args) throws Exception { + Map keyMap = RSAUtil.createKeys(3072); + String publicKey = keyMap.get("publicKey"); + String privateKey = keyMap.get("privateKey"); + System.out.println("公钥: \n\r" + publicKey); + System.out.println("私钥: \n\r" + privateKey); + } +} -- Gitee From 75b5792381d8b0c46a7233fd151a6a2a659c4b02 Mon Sep 17 00:00:00 2001 From: kaede10 Date: Tue, 12 Mar 2024 10:57:12 +0800 Subject: [PATCH 2/3] update OneidInterceptor.java --- .../common/interceptor/OneidInterceptor.java | 208 +++++++++--------- .../common/utils/HttpClientUtil.java | 1 - 2 files changed, 104 insertions(+), 105 deletions(-) diff --git a/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java index ed6e1a3..6f0c551 100644 --- a/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java +++ b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java @@ -34,11 +34,11 @@ public class OneidInterceptor implements HandlerInterceptor { @Value("${cookie.token.name}") private String cookieTokenName; - @Value("${cookie.token.domains}") - private String allowDomains; + // @Value("${cookie.token.domains}") + // private String allowDomains; - @Value("${cookie.token.secures}") - private String cookieSecures; + // @Value("${cookie.token.secures}") + // private String cookieSecures; @Value("${oneid.tokenBasePassword}") private String oneidTokenBasePassword; @@ -46,8 +46,8 @@ public class OneidInterceptor implements HandlerInterceptor { @Value("${oneid.permissionApi}") private String permissionApi; - @Value("${rsa.authing.privateKey}") - private String rsaAuthingPrivateKey; + // @Value("${rsa.authing.privateKey}") + // private String rsaAuthingPrivateKey; @Value("${oneid.manage.apiBody}") private String manageApiBody; @@ -83,11 +83,11 @@ public class OneidInterceptor implements HandlerInterceptor { throw new AuthException("unauthorized"); } - // 校验domain - String verifyDomainMsg = verifyDomain(httpServletRequest); - if (!verifyDomainMsg.equals("success")) { - throw new AuthException(verifyDomainMsg); - } + // // 校验domain + // String verifyDomainMsg = verifyDomain(httpServletRequest); + // if (!verifyDomainMsg.equals("success")) { + // throw new AuthException(verifyDomainMsg); + // } // 校验cookie Cookie tokenCookie = verifyCookie(httpServletRequest); @@ -95,40 +95,40 @@ public class OneidInterceptor implements HandlerInterceptor { throw new AuthException("unauthorized"); } - // 解密cookie中加密的token - String token = tokenCookie.getValue(); - try { - RSAPrivateKey privateKey = RSAUtil.getPrivateKey(rsaAuthingPrivateKey); - token = RSAUtil.privateDecrypt(token, privateKey); - } catch (Exception e) { - throw new AuthException("unauthorized"); - } - - // 解析token - String userId; - Date issuedAt; - Date expiresAt; - String permission; - String verifyToken; - try { - DecodedJWT decode = JWT.decode(token); - userId = decode.getAudience().get(0); - issuedAt = decode.getIssuedAt(); - expiresAt = decode.getExpiresAt(); - String permissionTemp = decode.getClaim("permission").asString(); - permission = new String(Base64.getDecoder().decode(permissionTemp.getBytes())); - verifyToken = decode.getClaim("verifyToken").asString(); - } catch (JWTDecodeException j) { - throw new AuthException("token error"); - } - - // 校验token - String verifyTokenMsg = verifyToken(headJwtTokenMd5, token, verifyToken, userId, issuedAt, expiresAt, - permission); - logger.info(verifyTokenMsg); - if (!verifyTokenMsg.equals("success")) { - throw new AuthException(verifyTokenMsg); - } + // // 解密cookie中加密的token + // String token = tokenCookie.getValue(); + // try { + // RSAPrivateKey privateKey = RSAUtil.getPrivateKey(rsaAuthingPrivateKey); + // token = RSAUtil.privateDecrypt(token, privateKey); + // } catch (Exception e) { + // throw new AuthException("unauthorized"); + // } + + // // 解析token + // String userId; + // Date issuedAt; + // Date expiresAt; + // String permission; + // String verifyToken; + // try { + // DecodedJWT decode = JWT.decode(token); + // userId = decode.getAudience().get(0); + // issuedAt = decode.getIssuedAt(); + // expiresAt = decode.getExpiresAt(); + // String permissionTemp = decode.getClaim("permission").asString(); + // permission = new String(Base64.getDecoder().decode(permissionTemp.getBytes())); + // verifyToken = decode.getClaim("verifyToken").asString(); + // } catch (JWTDecodeException j) { + // throw new AuthException("token error"); + // } + + // // 校验token + // String verifyTokenMsg = verifyToken(headJwtTokenMd5, token, verifyToken, userId, issuedAt, expiresAt, + // permission); + // logger.info(verifyTokenMsg); + // if (!verifyTokenMsg.equals("success")) { + // throw new AuthException(verifyTokenMsg); + // } // 校验查看版本兼容页面的权限 if (compatibleToken != null && compatibleToken.required()) { @@ -154,27 +154,27 @@ public class OneidInterceptor implements HandlerInterceptor { Object o, Exception e) throws Exception { } - private String verifyToken(String headerToken, String token, String verifyToken, - String userId, Date issuedAt, Date expiresAt, String permission) { - try { - if (!headerToken.equals(verifyToken)) { - return "unauthorized"; - } + // private String verifyToken(String headerToken, String token, String verifyToken, + // String userId, Date issuedAt, Date expiresAt, String permission) { + // try { + // if (!headerToken.equals(verifyToken)) { + // return "unauthorized"; + // } - if (expiresAt.before(new Date())) { - return "token expires"; - } + // if (expiresAt.before(new Date())) { + // return "token expires"; + // } - // token 签名密码验证 - String password = permission + oneidTokenBasePassword; - JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); - jwtVerifier.verify(token); + // // token 签名密码验证 + // String password = permission + oneidTokenBasePassword; + // JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); + // jwtVerifier.verify(token); - } catch (Exception e) { - return "unauthorized"; - } - return "success"; - } + // } catch (Exception e) { + // return "unauthorized"; + // } + // return "success"; + // } /** * 校验header中的token @@ -194,7 +194,7 @@ public class OneidInterceptor implements HandlerInterceptor { jwtVerifier.verify(headerToken); return DigestUtils.md5DigestAsHex(headerToken.getBytes()); } catch (Exception e) { - logger.error("verify h eadertoken exception", e); + logger.error("verify headertoken exception", e); return "unauthorized"; } } @@ -261,45 +261,45 @@ public class OneidInterceptor implements HandlerInterceptor { return cookie; } - /** - * 校验domain - * - * @param httpServletRequest request - * @return 是否可访问 - */ - private String verifyDomain(HttpServletRequest httpServletRequest) { - String referer = httpServletRequest.getHeader("referer"); - String origin = httpServletRequest.getHeader("origin"); - String[] domains = allowDomains.split(";"); - - boolean checkReferer = checkDomain(domains, referer); - boolean checkOrigin = checkDomain(domains, origin); - - if (!checkReferer && !checkOrigin) { - return "unauthorized"; - } - return "success"; - } - - private boolean checkDomain(String[] domains, String input) { - if (StringUtils.isBlank(input)) - return true; - int fromIndex; - int endIndex; - if (input.startsWith("http://")) { - fromIndex = 7; - endIndex = input.indexOf(":", fromIndex); - } else { - fromIndex = 8; - endIndex = input.indexOf("/", fromIndex); - endIndex = endIndex == -1 ? input.length() : endIndex; - } - String substring = input.substring(0, endIndex); - for (String domain : domains) { - if (substring.endsWith(domain)) - return true; - } - return false; - } + // /** + // * 校验domain + // * + // * @param httpServletRequest request + // * @return 是否可访问 + // */ + // private String verifyDomain(HttpServletRequest httpServletRequest) { + // String referer = httpServletRequest.getHeader("referer"); + // String origin = httpServletRequest.getHeader("origin"); + // String[] domains = allowDomains.split(";"); + + // boolean checkReferer = checkDomain(domains, referer); + // boolean checkOrigin = checkDomain(domains, origin); + + // if (!checkReferer && !checkOrigin) { + // return "unauthorized"; + // } + // return "success"; + // } + + // private boolean checkDomain(String[] domains, String input) { + // if (StringUtils.isBlank(input)) + // return true; + // int fromIndex; + // int endIndex; + // if (input.startsWith("http://")) { + // fromIndex = 7; + // endIndex = input.indexOf(":", fromIndex); + // } else { + // fromIndex = 8; + // endIndex = input.indexOf("/", fromIndex); + // endIndex = endIndex == -1 ? input.length() : endIndex; + // } + // String substring = input.substring(0, endIndex); + // for (String domain : domains) { + // if (substring.endsWith(domain)) + // return true; + // } + // return false; + // } } \ No newline at end of file diff --git a/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java b/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java index a3f1aef..46ca66d 100644 --- a/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java +++ b/src/main/java/com/easysoftware/common/utils/HttpClientUtil.java @@ -93,7 +93,6 @@ public class HttpClientUtil { httpPost.setEntity(stringEntity); HttpResponse response = httpClient.execute(httpPost); String responseBody = EntityUtils.toString(response.getEntity()); - logger.info("responseBody" + responseBody); return responseBody; } catch (Exception e) { throw new RuntimeException(MessageCode.EC0001.getMsgEn()); -- Gitee From 4ccbb99d971ef2912a3564706db0cfa214aef37b Mon Sep 17 00:00:00 2001 From: kaede10 Date: Tue, 12 Mar 2024 11:04:15 +0800 Subject: [PATCH 3/3] update OneidInterceptor.java --- .../common/interceptor/OneidInterceptor.java | 57 +++--- .../easysoftware/common/utils/RSAUtil.java | 176 ------------------ 2 files changed, 28 insertions(+), 205 deletions(-) delete mode 100644 src/main/java/com/easysoftware/common/utils/RSAUtil.java diff --git a/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java index 6f0c551..d215237 100644 --- a/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java +++ b/src/main/java/com/easysoftware/common/interceptor/OneidInterceptor.java @@ -12,7 +12,6 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.easysoftware.common.exception.AuthException; import com.easysoftware.common.utils.HttpClientUtil; import com.easysoftware.common.utils.ObjectMapperUtil; -import com.easysoftware.common.utils.RSAUtil; import com.fasterxml.jackson.databind.JsonNode; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; @@ -40,8 +39,8 @@ public class OneidInterceptor implements HandlerInterceptor { // @Value("${cookie.token.secures}") // private String cookieSecures; - @Value("${oneid.tokenBasePassword}") - private String oneidTokenBasePassword; + // @Value("${oneid.tokenBasePassword}") + // private String oneidTokenBasePassword; @Value("${oneid.permissionApi}") private String permissionApi; @@ -77,11 +76,11 @@ public class OneidInterceptor implements HandlerInterceptor { return true; } - String headerToken = httpServletRequest.getHeader("token"); - String headJwtTokenMd5 = verifyHeaderToken(headerToken); - if (StringUtils.isBlank(headJwtTokenMd5) || headJwtTokenMd5.equals("unauthorized") ) { - throw new AuthException("unauthorized"); - } + // String headerToken = httpServletRequest.getHeader("token"); + // String headJwtTokenMd5 = verifyHeaderToken(headerToken); + // if (StringUtils.isBlank(headJwtTokenMd5) || headJwtTokenMd5.equals("unauthorized") ) { + // throw new AuthException("unauthorized"); + // } // // 校验domain // String verifyDomainMsg = verifyDomain(httpServletRequest); @@ -176,28 +175,28 @@ public class OneidInterceptor implements HandlerInterceptor { // return "success"; // } - /** - * 校验header中的token - * - * @param headerToken header中的token - * @return 校验正确返回token的MD5值 - */ - private String verifyHeaderToken(String headerToken) { - try { - if (StringUtils.isBlank(headerToken)) { - return "unauthorized"; - } + // /** + // * 校验header中的token + // * + // * @param headerToken header中的token + // * @return 校验正确返回token的MD5值 + // */ + // private String verifyHeaderToken(String headerToken) { + // try { + // if (StringUtils.isBlank(headerToken)) { + // return "unauthorized"; + // } - // token 签名密码验证 - String password = oneidTokenBasePassword; - JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); - jwtVerifier.verify(headerToken); - return DigestUtils.md5DigestAsHex(headerToken.getBytes()); - } catch (Exception e) { - logger.error("verify headertoken exception", e); - return "unauthorized"; - } - } + // // token 签名密码验证 + // String password = oneidTokenBasePassword; + // JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build(); + // jwtVerifier.verify(headerToken); + // return DigestUtils.md5DigestAsHex(headerToken.getBytes()); + // } catch (Exception e) { + // logger.error("verify headertoken exception", e); + // return "unauthorized"; + // } + // } /** * 校验用户操作权限 diff --git a/src/main/java/com/easysoftware/common/utils/RSAUtil.java b/src/main/java/com/easysoftware/common/utils/RSAUtil.java deleted file mode 100644 index 5eb9905..0000000 --- a/src/main/java/com/easysoftware/common/utils/RSAUtil.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.easysoftware.common.utils; - -import java.io.ByteArrayOutputStream; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.security.*; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; -import javax.crypto.Cipher; -import javax.crypto.NoSuchPaddingException; -import org.apache.commons.codec.binary.Base64; -import org.apache.tomcat.util.http.fileupload.IOUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - - -@Component -public class RSAUtil implements Serializable { - public static String KEY_ALGORITHM; - public static String RSA_ALGORITHM; - - @Value("${rsa.key.algorithm:RSA}") - public void setKeyAlgorithm(String keyAlgorithm) { RSAUtil.KEY_ALGORITHM = keyAlgorithm; } - - @Value("${rsa.authing.algorithm}") - public void setRsaAlgorithm(String rsaAlgorithm) { RSAUtil.RSA_ALGORITHM = rsaAlgorithm; } - - /** - * 随机生成密钥对(公钥和私钥) - * - * @param keySize 密钥长度 - */ - public static Map createKeys(int keySize) throws NoSuchAlgorithmException { - //为RSA算法创建一个KeyPairGenerator对象 - KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM); - //初始化KeyPairGenerator对象,密钥长度 - kpg.initialize(keySize); - //生成密匙对 - KeyPair keyPair = kpg.generateKeyPair(); - //得到公钥 - Key publicKey = keyPair.getPublic(); - String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded()); - //得到私钥 - Key privateKey = keyPair.getPrivate(); - String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded()); - - Map keyPairMap = new HashMap<>(); - keyPairMap.put("publicKey", publicKeyStr); - keyPairMap.put("privateKey", privateKeyStr); - return keyPairMap; - } - - /** - * 获取公钥 - * - * @param publicKey 密钥字符串(经过base64编码) - */ - public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException { - // 通过X509编码的Key指令获得公钥对象 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); - return (RSAPublicKey) keyFactory.generatePublic(x509KeySpec); - } - - /** - * 获取私钥 - * - * @param privateKey 密钥字符串(经过base64编码) - */ - public static RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException { - //通过PKCS#8编码的Key指令获得私钥对象 - KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); - return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec); - } - - /** - * 公钥加密 - * - * @param data 明文 - * @param publicKey 公钥 - */ - public static String publicEncrypt(String data, RSAPublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(StandardCharsets.UTF_8), publicKey.getModulus().bitLength())); - } - - /** - * 私钥解密 - * - * @param data 密文 - * @param privateKey 私钥 - */ - public static String privateDecrypt(String data, RSAPrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), StandardCharsets.UTF_8); - } - - /** - * 私钥加密 - * - * @param data 明文 - * @param privateKey 私钥 - */ - public static String privateEncrypt(String data, RSAPrivateKey privateKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - return Base64.encodeBase64URLSafeString(rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(StandardCharsets.UTF_8), privateKey.getModulus().bitLength())); - } - - /** - * 公钥解密 - * - * @param data 密文 - * @param publicKey 公钥 - */ - public static String publicDecrypt(String data, RSAPublicKey publicKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException { - Cipher cipher = Cipher.getInstance(RSA_ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), publicKey.getModulus().bitLength()), StandardCharsets.UTF_8); - } - - /** - * 对数据分段加密码、解密 - * - * @param cipher 密码服务 - * @param opmode 加密 or 解密 - * @param datas 需要加密或者解密的内容 - * @param keySize 密钥长度 - */ - private static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) { - int maxBlock = 0; - if (opmode == Cipher.DECRYPT_MODE) { - maxBlock = keySize / 8; - } else { - maxBlock = keySize / 8 - 2 * 32 - 2; - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int offSet = 0; - byte[] buff; - int i = 0; - try { - while (datas.length > offSet) { - if (datas.length - offSet > maxBlock) { - buff = cipher.doFinal(datas, offSet, maxBlock); - } else { - buff = cipher.doFinal(datas, offSet, datas.length - offSet); - } - out.write(buff, 0, buff.length); - i++; - offSet = i * maxBlock; - } - } catch (Exception e) { - throw new RuntimeException("Cipher Mode: " + opmode + " Error", e); - } - byte[] dataResult = out.toByteArray(); - IOUtils.closeQuietly(out); - return dataResult; - } - - public static void main(String[] args) throws Exception { - Map keyMap = RSAUtil.createKeys(3072); - String publicKey = keyMap.get("publicKey"); - String privateKey = keyMap.get("privateKey"); - System.out.println("公钥: \n\r" + publicKey); - System.out.println("私钥: \n\r" + privateKey); - } -} -- Gitee