跟随上一篇的Gson序列化器方法的重写,涉及到了JWT的加密;
首先先简单介绍一下JWT:JWT是json web token缩写。它将用户信息加密到token里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证。
优点是在分布式系统中,很好地解决了单点登录问题,很容易解决了session共享的问题。
缺点是无法作废已颁布的令牌/不易应对数据过期。
这里我们使用JWT对文件路径进行了加密,token失效时间为3分钟,接下来直接看代码吧:
首先POM文件里面引入依赖
1 <dependency>
2 <groupId>com.auth0</groupId>
3 <artifactId>java-jwt</artifactId>
4 <version>3.3.0</version>
5 </dependency>
然后编辑自己的加密工具类:CommonEnctyptUtil.java
import com.alibaba.fastjson.JSONObject;
import com.apollo.alds.util.ConvertionUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.log4j.Logger;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* @Auther: SHIYIXIN
* @Date: 2018/11/26 16:10
* @Description: 文件名称加密工具类
*/
public class CommonEnctyptUtil {
private static final Logger LOG = Logger.getLogger(CommonEnctyptUtil.class);
private static final String KEY="DF94CBDCA294DC5DEF1368E64313FD3B98FE5EBCAB7F23AE";
private static String getMessage(int code) {
switch (code) {
case 1:
return "解密失败!";
case 2:
return "token为空无效";
case 3:
return "token无效或已过期";
default:
return "其他未知错误";
}
}
/**
* 文件加密
* @param fileName 文件名
* @param minutes token 过期时间
* @return 加密后文件名
*/
public static String getAESResult(String fileName,int minutes){
String result="";
JSONObject json=new JSONObject();
json.put("fileName",fileName);
String token="";
try {
token=getToken(fileName,minutes);
System.out.println("token="+token);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if(!"".equals(token)){
json.put("token",token);
}
result= AESUtil.encrypt(KEY, json.toJSONString());
LOG.info("getAESResult="+result);
return result;
}
/**
*
* @param fileName 文件名
* @param minutes 过期时间
* @return
* @throws UnsupportedEncodingException
*/
public static String getToken( String fileName,int minutes) throws UnsupportedEncodingException {
LOG.info("fileName:" + fileName);
LOG.info("minutes:" + minutes);
final Calendar instance = Calendar.getInstance();
instance.add(Calendar.MINUTE, minutes);
Algorithm algorithm = Algorithm.HMAC256("secret");
String token = JWT.create().withClaim("fileName", fileName).withIssuer("auth0")
.withExpiresAt(instance.getTime()).sign(algorithm);
LOG.info("getToken="+token);
return token;
}
/**
* 密文解密
* @param info 加密字符串
* @return
*/
public static Map getDecryptInfo(String info){
Map result=new HashMap();
boolean res=false;
int code=0;
String msg="";
LOG.info("getDecryptInfo-----"+info);
String message=AESUtil.decrypt(KEY, info);//解密
LOG.info("解密后信息:{}"+message);
if(message!=null&&!"".equals(message)){
JSONObject json=JSONObject.parseObject(message);
String token= ConvertionUtil.getSimpleStringWithNull(json.get("token"));
String fileName=ConvertionUtil.getSimpleStringWithNull(json.get("fileName"));
if(!"".equals(token)){
if(checktoken(fileName,token)){
res=true;
msg=fileName;
}else{
code=3;
msg=getMessage(code);
}
}else{
code=2;
msg=getMessage(code);
}
}else{
code=1;
msg=getMessage(code);
}
result.put("result",res);
result.put("code",code);
result.put("msg",msg);
LOG.info("getDecryptResult-----"+result);
return result;
}
public static boolean checktoken(String fileName,String token) {
LOG.info("fileName:" + fileName);
boolean result=false;
try {
Algorithm algorithm = Algorithm.HMAC256("secret");
JWTVerifier verifier = JWT.require(algorithm).withIssuer("auth0").withClaim("fileName", fileName).build(); // Reusable verifier instance
// 这里需注意的是,依赖的fasterxml.jackson.core 的版本必须是2.9.2以上的
DecodedJWT jwt = verifier.verify(token);
result=true;
} catch (JWTVerificationException ex) {
// log
LOG.info("authcheckfailed:", ex);
} catch (UnsupportedEncodingException e) {
LOG.info("编码错误:", e);
} catch (Exception e){
LOG.info("checktokenerror",e);
}
return result;
}
}
AESUtil类:
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
/**
* @Auther: shiyixin
* @Date: 2018/11/26 15:45
* @Description:
*/
public class AESUtil {
private static final Logger logger = Logger.getLogger(AESUtil.class);
private static final String defaultCharset = "UTF-8";
private static final String KEY_AES = "AES";
private static final String KEY = "123456";
/**
* 加密
*
* @param data 需要加密的内容
* @param key 加密密码
* @return
*/
public static String encrypt(String key,String data ) {
return doAES(data, key, Cipher.ENCRYPT_MODE);
}
/**
* 解密
*
* @param data 待解密内容
* @param key 解密密钥
* @return
*/
public static String decrypt(String key,String data ) {
return doAES(data, key, Cipher.DECRYPT_MODE);
}
/**
* 加解密
*
* @param data 待处理数据
* @param
* @param mode 加解密mode
* @return
*/
private static String doAES(String data, String key, int mode) {
try {
if (StringUtils.isBlank(data) || StringUtils.isBlank(key)) {
return null;
}
//判断是加密还是解密
boolean encrypt = mode == Cipher.ENCRYPT_MODE;
byte[] content;
//true 加密内容 false 解密内容
if (encrypt) {
content = data.getBytes(defaultCharset);
} else {
content = parseHexStr2Byte(data);
}
//1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator kgen = KeyGenerator.getInstance(KEY_AES);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
//2.根据ecnodeRules规则初始化密钥生成器
//生成一个128位的随机源,根据传入的字节数组
kgen.init(128, random);
//3.产生原始对称密钥
SecretKey secretKey = kgen.generateKey();
//4.获得原始对称密钥的字节数组
byte[] enCodeFormat = secretKey.getEncoded();
//5.根据字节数组生成AES密钥
SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, KEY_AES);
//6.根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器
//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
cipher.init(mode, keySpec);// 初始化
byte[] result = cipher.doFinal(content);
if (encrypt) {
//将二进制转换成16进制
return parseByte2HexStr(result);
} else {
return new String(result, defaultCharset);
}
} catch (Exception e) {
}
return null;
}
/**
* 将二进制转换成16进制
*
* @param buf
* @return
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*
* @param hexStr
* @return
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1) {
return null;
}
byte[] result =null;
try {
result= new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
}catch(Exception e){
logger.info("parseHexStr2Byte密文处理异常");
}
return result;
}
}
由于这个加密文件没有经过我手去写,我顺便加了注释进去,希望对大家能有帮助,可以得话记得添加一下关注,谢谢!