项目场景:

项目场景:基于Spring Security 实现安全认证功能

什么是SpringSecurity?

  • spring.io提供的安全管理框架,主要功能包括但不限于:安全认证、权限管理等。是保护基于 Spring的应用程序 的标准

官方话语:

  1. 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一个用来处理各系统二进制兼容编码方式

编码表:

在这里插入图片描述

编码方式:

  1. 使用 Base64 进行编码,大致可以分为 4 步:
  2. 将原始数据每三个字节作为一组,每个字节是8个bit,所以一共是 24 个 bit,将 24 个 bit 分为四组,每组 6 个 bit
  3. 在每组前面加补 00,将其补全成四组8个bit,到此步,原生数据的3个字节已经变成4个字节了,增大了将近30%
  4. 根据Base64码表得到扩展后每个字节的对应符号

使用场景:

  1. 证书
  2. 网页中的一些小图片,可以直接以 base64 编码的方式嵌入
  3. 电子邮件的附件,因为附件往往有不可见字符

Base64技术文档:https://developer.mozilla.org/zh-CN/docs/Glossary/Base64


解决方案:

说了那么多,最后解决方案是什么呢?那就是:

  • 编码字符采用:偶数位字符
    在这里插入图片描述
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐