Base64: java.lang.IllegalArgumentException: 非法字符

Base64: java.lang.IllegalArgumentException: Illegal character

我正在尝试在用户注册后发送确认电子邮件。为此,我正在使用 JavaMail 库和 Java 8 Base64 util class.

我按以下方式对用户电子邮件进行编码:

byte[] encodedEmail = Base64.getUrlEncoder().encode(user.getEmail().getBytes(StandardCharsets.UTF_8));
Multipart multipart = new MimeMultipart();
InternetHeaders headers = new InternetHeaders();
headers.addHeader("Content-type", "text/html; charset=UTF-8");
String confirmLink = "Complete your registration by clicking on following"+ "\n<a href='" + confirmationURL + encodedEmail + "'>link</a>";
MimeBodyPart link = new MimeBodyPart(headers,
confirmLink.getBytes("UTF-8"));
multipart.addBodyPart(link);

其中 confirmationURL 是:

private final static String confirmationURL = "http://localhost:8080/project/controller?command=confirmRegistration&ID=";

然后在 ConfirmRegistrationCommand 中以这种方式解码:

    String encryptedEmail = request.getParameter("ID");

    String decodedEmail = new String(Base64.getUrlDecoder().decode(encryptedEmail), StandardCharsets.UTF_8);

    RepositoryFactory repositoryFactory = RepositoryFactory
            .getFactoryByName(FactoryType.MYSQL_REPOSITORY_FACTORY);
    UserRepository userRepository = repositoryFactory.getUserRepository();
    User user = userRepository.find(decodedEmail);

    if (user.getEmail().equals(decodedEmail)) {
        user.setActiveStatus(true);
        return Path.WELCOME_PAGE;
    } else {
        return Path.ERROR_PAGE;
    }

当我尝试解码时:

http://localhost:8080/project/controller?command=confirmRegistration&ID=[B@6499375d

我得到 java.lang.IllegalArgumentException: Illegal base64 character 5b

我尝试使用基本的 Encode/Decoder(不是 URL)但没有成功。

已解决:

问题出在下一行:

 String confirmLink = "Complete your registration by clicking on following"+ "\n<a href='" + confirmationURL + encodedEmail + "'>link</a>";

我在字节数组上调用 toString,所以我应该执行以下操作:

String encodedEmail = new String(Base64.getEncoder().encode(
                user.getEmail().getBytes(StandardCharsets.UTF_8)));

感谢 Jon SkeetByteHamster

您的编码文本是 [B@6499375d。那不是 Base64,编码 时出了点问题。那个解码码看起来不错

使用此代码将 byte[] 转换为字符串,然后再将其添加到 URL:

String encodedEmailString = new String(encodedEmail, "UTF-8");
// ...
String confirmLink = "Complete your registration by clicking on following"
    + "\n<a href='" + confirmationURL + encodedEmailString + "'>link</a>";

Base64.Encoder.encodeToString 方法自动使用 ISO-8859-1 字符集。

对于我写的一个加密工具,我把输入的密文字符串和Base64编码传输,然后逆向过程。相关部分如下所示。 注意:我的 file.encoding 属性 在调用 JVM 时设置为 ISO-8859-1,因此这也可能有影响。

static String getBase64EncodedCipherText(String cipherText) {
    byte[] cText = cipherText.getBytes();
    // return an ISO-8859-1 encoded String
    return Base64.getEncoder().encodeToString(cText);
}

static String getBase64DecodedCipherText(String encodedCipherText) throws IOException {
    return new String((Base64.getDecoder().decode(encodedCipherText)));
}

public static void main(String[] args) {
    try {
        String cText = getRawCipherText(null, "Hello World of Encryption...");

        System.out.println("Text to encrypt/encode: Hello World of Encryption...");
        // This output is a simple sanity check to display that the text
        // has indeed been converted to a cipher text which 
        // is unreadable by all but the most intelligent of programmers.
        // It is absolutely inhuman of me to do such a thing, but I am a
        // rebel and cannot be trusted in any way.  Please look away.
        System.out.println("RAW CIPHER TEXT: " + cText);
        cText = getBase64EncodedCipherText(cText);
        System.out.println("BASE64 ENCODED: " + cText);
        // There he goes again!!
        System.out.println("BASE64 DECODED:  " + getBase64DecodedCipherText(cText));
        System.out.println("DECODED CIPHER TEXT: " + decodeRawCipherText(null, getBase64DecodedCipherText(cText)));
    } catch (Exception e) {
        e.printStackTrace();
    }

}

输出如下:

Text to encrypt/encode: Hello World of Encryption...
RAW CIPHER TEXT: q$;�C�l��<8��U���X[7l
BASE64 ENCODED: HnEPJDuhQ+qDbInUCzw4gx0VDqtVwef+WFs3bA==
BASE64 DECODED:  q$;�C�l��<8��U���X[7l``
DECODED CIPHER TEXT: Hello World of Encryption...

我遇到了这个错误,因为我的编码图像以 data:image/png;base64,iVBORw0... 开头。

This answer 引导我找到解决方案:

String partSeparator = ",";
if (data.contains(partSeparator)) {
  String encodedImg = data.split(partSeparator)[1];
  byte[] decodedImg = Base64.getDecoder().decode(encodedImg.getBytes(StandardCharsets.UTF_8));
  Path destinationFile = Paths.get("/path/to/imageDir", "myImage.png");
  Files.write(destinationFile, decodedImg);
}

该代码删除了 Base64 编码图像前面的元数据,并将 Base64 字符串传递给 Java 的 Base64.Decoder 以获取字节形式的图像。

只需使用以下代码即可解决此问题:

JsonObject obj = Json.createReader(new ByteArrayInputStream(Base64.getDecoder().decode(accessToken.split("\.")[1].
                        replace('-', '+').replace('_', '/')))).readObject();

在上面的代码中 replace('-', '+').replace('_', '/') 完成了这项工作。有关详细信息,请参阅 https://jwt.io/js/jwt.js。我从 link:

获得的代码部分理解了问题
function url_base64_decode(str) {
  var output = str.replace(/-/g, '+').replace(/_/g, '/');
  switch (output.length % 4) {
    case 0:
      break;
    case 2:
      output += '==';
      break;
    case 3:
      output += '=';
      break;
    default:
      throw 'Illegal base64url string!';
  }
  var result = window.atob(output); //polifyll https://github.com/davidchambers/Base64.js
  try{
    return decodeURIComponent(escape(result));
  } catch (err) {
    return result;
  }
}

我的 Linux Jenkins slave 出现了这个错误。我通过将节点从 "Known hosts file Verification Strategy" 更改为 "Non verifying Verification Strategy".

来修复它

我在这里添加了我的失败和发现以及我是如何克服这个问题的。 我最近一直在使用 SpringBoot 进行 JASYPT 加密,我遇到了许多问题并在此过程中修复了它们。 对于非法字符异常这个问题,我已经记录了 my answer is here for another thread.

此外,我在此处添加了 another answer,它与 JASYP 加密相关,与此问题无关,只是对同一上下文的引用。随意跳过。希望这些发现能有所帮助并节省一些时间。