在 Google 云上部署加密 Java 云函数时出错

Error deploying Encryption Java cloud function on Google cloud

尝试在 Google 云上部署加密 java 云函数时遇到以下错误。 [注意,功能在本地工作]。

Exception in thread "main" java.lang.NoClassDefFoundError: com/nimbusds/jose/JWEEncrypter at java.base/java.lang.Class.getDeclaredConstructors0(Native Method) at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3137) at java.base/java.lang.Class.getConstructor0(Class.java:3342) at java.base/java.lang.Class.getConstructor(Class.java:2151) at com.google.cloud.functions.invoker.HttpFunctionExecutor.forClass(HttpFunctionExecutor.java:53) at com.google.cloud.functions.invoker.runner.Invoker.startServer(Invoker.java:243) at com.google.cloud.functions.invoker.runner.Invoker.main(Invoker.java:121) Caused by: java.lang.ClassNotFoundException: com.nimbusds.jose.JWEEncrypter at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 7 more
Exception in thread "main" java.lang.NoClassDefFoundError: com/nimbusds/jose/JWEEncrypter at java.base/java.lang.Class.getDeclaredConstructors0(Native Method) at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3137) at java.base/java.lang.Class.getConstructor0(Class.java:3342) at java.base/java.lang.Class.getConstructor(Class.java:2151) at com.google.cloud.functions.invoker.HttpFunctionExecutor.forClass(HttpFunctionExecutor.java:53) at com.google.cloud.functions.invoker.runner.Invoker.startServer(Invoker.java:243) at com.google.cloud.functions.invoker.runner.Invoker.main(Invoker.java:121) Caused by: java.lang.ClassNotFoundException: com.nimbusds.jose.JWEEncrypter at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) 

使用 nimbus-jose-jwt jar。也尝试了多个版本的 jar。但是,面临同样的错误。 下面是在 pom.xml:

中添加的片段
    <dependency>
            <groupId>com.nimbusds</groupId>
            <artifactId>nimbus-jose-jwt</artifactId>
            <version>9.15.2</version>
    </dependency>

Java 运行时间:Java 11。 添加以下功能代码:

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.http.HttpStatus;
import java.security.interfaces.*;
import javax.crypto.*;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;
import java.util.*;
import java.security.KeyFactory;
import java.security.spec.X509EncodedKeySpec;
import java.io.File;
import java.security.PublicKey;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.DataInputStream;
public class Encrypt implements HttpFunction {

  private static final Gson gson = new Gson();
  private static final Logger logger = Logger.getLogger(
      Encrypt.class.getName());

  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    PrintWriter writer = new PrintWriter(response.getWriter());

    String contentType = request.getContentType().orElse("");
    String plaintext, ciphertext = "";
    String jwtString="";
    try {
      JsonObject body = gson.fromJson(request.getReader(), JsonObject.class);
      plaintext = body.toString();
      logger.log(Level.INFO, "Plaintext: " + plaintext);
      RSAPublicKey publicKey = getPublicKey();
      Date now = new Date();
      // convert json object to map
      Map<String, Object> claims = gson.fromJson(plaintext, HashMap.class);
      System.out.println("claims: "+claims);
  
      JWTClaimsSet jwtClaims;
      jwtClaims=generate(claims);
      
      System.out.println("jwtClaims: " + jwtClaims);
   
      System.out.println(jwtClaims.toJSONObject());
  
      JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
          .type(JOSEObjectType.JWT).build();

      EncryptedJWT jwt = new EncryptedJWT(header, jwtClaims);

      RSAEncrypter encrypter = new RSAEncrypter(((RSAPublicKey)(publicKey)));

      jwt.encrypt(encrypter);

       jwtString = jwt.serialize();

      System.out.println(jwtString);

      jwt = EncryptedJWT.parse(jwtString);

      response.setStatusCode(HttpURLConnection.HTTP_OK);
    } catch (Exception e) {
      logger.severe("Error parsing JSON: " + e.getMessage());
    }
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("payload", jwtString);
    String mapAsString = map
        .keySet()
        .stream()
        .map(key -> "\"" + key + "\":\"" + map.get(key) + "\"")
        .collect(Collectors.joining(", ", "{", "}"));
    logger.log(Level.INFO, "mapAsString: " + mapAsString);
    writer.printf(mapAsString);
  }


  public static RSAPublicKey getPublicKey() {
    try {

      String publicKeyString = "aaa";
      publicKeyString = publicKeyString.trim();
      // byte[] publicKeyBytes=publicKeyString.getBytes();
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");

      byte[] decoded = Base64.getDecoder().decode(publicKeyString);
      X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(decoded);
      RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
      return publicKey;
    } catch (Exception e) {

      e.printStackTrace();
      return null;
    }
  }

  public JWTClaimsSet generate(final Map<String, Object> claims) {
    // claims builder
    final JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder();
    // add claims
    for (final Map.Entry<String, Object> entry : claims.entrySet()) {
      builder.claim(entry.getKey(), entry.getValue());
    }

    return builder.build();
  }

  public static void main(String[] args) {
  }

}

在部署之前也尝试过“mvn clean package”。仍然面临同样的问题。

部署错误:

您的错误表明您正在尝试使用不存在的 class。如果它在本地工作并且在 Google 云上不工作,则意味着 libraries/jar 配置不正确。

如果您要部署的是 Fat/Uber jar,请解压缩 jar 并验证 nimbus-jose-jwt 的位置。

An uber JAR is a JAR file that contains the function classes as well as all of its dependencies. You can build an uber JAR with both Maven and Gradle

如果您要部署的是 Thin Jar,请确保您的依赖项位于与部署的 JAR 相关的包中。

A thin JAR is a JAR file that contains only the function classes without the dependencies embedded in the same JAR file. Because the dependencies are still needed for deployment, you need to set things up as follows:

The dependencies must be in a subdirectory relative to the JAR to be deployed. The JAR must have a META-INF/MANIFEST.MF file that includes a Class-Path attribute whose value lists the required dependency paths.

Google 云文档非常清楚地说明了如何使用 Maven/Gradle 进行部署。

https://cloud.google.com/functions/docs/concepts/java-deploy#deploy_from_a_jar