错误日志 | java.lang.IllegalArgumentException: Last unit does not have enough valid bits
项目场景:基于Spring Security 实现安全认证功能什么是SpringSecurity?
·
项目场景:
项目场景:基于Spring Security 实现安全认证功能
什么是SpringSecurity?
- spring.io提供的安全管理框架,主要功能包括但不限于:安全认证、权限管理等。是保护基于 Spring的应用程序 的标准
官方话语:
- Spring Security是一个Java框架,用于保护应用程序的安全性。它提供了一套全面的安全解决方案,包括身份验证、授权、防止攻击等功能。
问题描述
问题:
- java.lang.IllegalArgumentException: Last unit does not have enough valid bits
译文:
最后一个单元没有足够的有效位
解决办法:需要Base64加密的字符,保持为偶数。
java.lang.lllegalArgumentException?
IllegalArgumentException是Java中的一个异常类,用于表示程序中的一个方法被传递了一个不合法的参数,即参数的值不符合该方法预期的取值范围或类型。
既然是web安全认证,那必然少不了jwt了。
JWT是JSON Web Token的缩写,它是一种开源标准(RFC 7519),用来定义通信双方如何安全地交换信息的格式。
从上面一段话中我们可以得出:
- jwt是一个标准
- 定义通信双方交换信息的格式
我的问题就出现在信息加密格式这里了。出了问题怎么办?直接看源码:JwtUtil(开玩笑的了,遇到问题,那当然是先调试 debug了):
package com.crocodile.individual.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
public class JwtUtil {
public static final long JWT_TTL = 60*60*1000L;
// 问题的源头,
public static final String JWT_KEY = "crocodiles";
public static String getUUID(){
String token = UUID.randomUUID().toString().replaceAll("-", "");
return token;
}
//base64加密报错,根本原因:编码后的URL长度不符合要求(要求长度是4的倍数)
public static SecretKey generalKey(){
byte[] encodeKey = Base64.getDecoder().decode(JWT_KEY);
SecretKeySpec key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
return key;
}
public static Claims parseJwt(String jwt) throws Exception{
SecretKey secretKey = generalKey();
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody();
}
/**
* create jwt
*/
public static String createJwt(String subject){
JwtBuilder jwtBuilder = getJwtBuilder(subject, getUUID());
return jwtBuilder.compact();
}
/**
* 封装jwt
*/
public static JwtBuilder getJwtBuilder(String subject,String UUid){
SignatureAlgorithm algorithm = SignatureAlgorithm.HS256;
SecretKey secretKey = generalKey();
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
long expMillis = nowMillis + JWT_TTL;
Date expDate = new Date(expMillis);
return Jwts.builder()
.setId(UUid)
.setSubject(subject)
.setIssuer("crq")
.setIssuedAt(now)
.signWith(algorithm,secretKey)
.setExpiration(expDate);
}
}
原因分析:
我去了解了一下base64是什么?得到了一下结果:
- Base64是一种二进制到文本的编码方式,byte到String 的编码方式,编码出的字符串只包含ASCII基础字符。
- 其编码后的文本只包含64个ASCII码字符
- Base64就是为了解决各系统以及传输协议中二进制不兼容的问题而生的。
从上面三句话,能得出:
- Base64一个用来处理各系统二进制兼容的编码方式
编码表:
编码方式:
- 使用 Base64 进行编码,大致可以分为 4 步:
- 将原始数据每三个字节作为一组,每个字节是8个bit,所以一共是 24 个 bit,将 24 个 bit 分为四组,每组 6 个 bit
- 在每组前面加补 00,将其补全成四组8个bit,到此步,原生数据的3个字节已经变成4个字节了,增大了将近30%
- 根据Base64码表得到扩展后每个字节的对应符号
使用场景:
- 证书
- 网页中的一些小图片,可以直接以 base64 编码的方式嵌入
- 电子邮件的附件,因为附件往往有不可见字符
Base64技术文档:https://developer.mozilla.org/zh-CN/docs/Glossary/Base64
解决方案:
说了那么多,最后解决方案是什么呢?那就是:
- 编码字符采用:偶数位字符
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献1条内容
所有评论(0)