209 lines
7.7 KiB
Java
209 lines
7.7 KiB
Java
package com.peanut.common.utils;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
|
||
import com.peanut.modules.common.dao.VodAesTokenDao;
|
||
import com.peanut.modules.common.entity.VodAesTokenEntity;
|
||
import lombok.Data;
|
||
import java.util.Base64;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.stereotype.Component;
|
||
|
||
import javax.crypto.Cipher;
|
||
import javax.crypto.spec.IvParameterSpec;
|
||
import javax.crypto.spec.SecretKeySpec;
|
||
import java.util.Arrays;
|
||
import java.util.List;
|
||
|
||
@Component
|
||
public class PlayToken {
|
||
|
||
@Autowired
|
||
private VodAesTokenDao vodAesTokenDao;
|
||
|
||
//非AES生成方式,无需以下参数
|
||
private static String ENCRYPT_KEY = "abcdefgh#$&!mnopqrstuvwxyz123456"; //加密Key,为用户自定义的字符串,长度为16、24或32位
|
||
private static String INIT_VECTOR = "ABCDEFGHIJKLMNOP"; //加密偏移量,为用户自定义字符串,长度为16位,不能含有特殊字符
|
||
|
||
// public static void main(String[] args) throws Exception {
|
||
//
|
||
// String serviceId = "12";
|
||
// PlayToken playToken = new PlayToken();
|
||
// String aesToken = playToken.generateToken(serviceId);
|
||
// //System.out.println("aesToken " + aesToken);
|
||
// //System.out.println(playToken.validateToken(aesToken)); //验证解密部分
|
||
//
|
||
// }
|
||
/**
|
||
* 根据传递的参数生成令牌
|
||
* 说明:
|
||
* 1、参数可以是业务方的用户ID、播放终端类型等信息
|
||
* 2、调用令牌接口时生成令牌Token
|
||
* @return
|
||
*/
|
||
public String generateToken() throws Exception {
|
||
// if (null == args || args.length <= 0) {
|
||
// return null;
|
||
// }
|
||
// String base = StringUtils.join(Arrays.asList(args), "_");
|
||
int bas = (int)(Math.random()*90+10);
|
||
String base = String.valueOf(bas);
|
||
//设置60S后,该token过期,过期时间可以自行调整
|
||
long expire = System.currentTimeMillis() + 60000L;
|
||
base += "_" + expire; //自定义字符串,base的长度为16位字符(此例中,时间戳占13位,下划线(_)占1位,则还需传入2位字符。实际配置时也可按需全部更改,最终保证base为16、24或32位字符串即可。)
|
||
//生成token
|
||
String token = encrypt(base); //arg1为要加密的自定义字符串,arg2为加密Key
|
||
//保存token,用于解密时校验token的有效性,例如:过期时间、token的使用次数
|
||
saveToken(token);
|
||
return token;
|
||
}
|
||
|
||
/**
|
||
* 验证token的有效性
|
||
* 说明:
|
||
* 1、解密接口在返回播放密钥前,需要先校验Token的合法性和有效性
|
||
* 2、强烈建议同时校验Token的过期时间以及Token的有效使用次数
|
||
* @param token
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
public boolean validateToken(String token) throws Exception {
|
||
if (null == token || "".equals(token)) {
|
||
return false;
|
||
}
|
||
String base = decrypt(token); //arg1为解密字符串,arg2为解密Key
|
||
//先校验token的有效时间
|
||
Long expireTime = Long.valueOf(base.substring(base.lastIndexOf("_") + 1));
|
||
// System.out.println("时间校验:" + expireTime);
|
||
if (System.currentTimeMillis() > expireTime) {
|
||
return false;
|
||
}
|
||
//从DB获取token信息,判断token的有效性,业务方可自行实现
|
||
VodAesTokenEntity dbToken = getToken(token);
|
||
//判断是否已经使用过该token
|
||
if (dbToken == null || dbToken.getUseCount() > 0) {
|
||
return false;
|
||
}
|
||
dbToken.setUseCount(1);
|
||
vodAesTokenDao.updateById(dbToken);
|
||
//获取到业务属性信息,用于校验
|
||
String businessInfo = base.substring(0, base.lastIndexOf("_"));
|
||
String[] items = businessInfo.split("_");
|
||
//校验业务信息的合法性,业务方实现
|
||
return validateInfo(items);
|
||
}
|
||
/**
|
||
* 保存Token到DB
|
||
* 业务方自行实现
|
||
*
|
||
* @param token
|
||
*/
|
||
public void saveToken(String token) {
|
||
VodAesTokenEntity vodAesTokenEntity = new VodAesTokenEntity();
|
||
vodAesTokenEntity.setToken(token);
|
||
vodAesTokenDao.insert(vodAesTokenEntity);
|
||
//TODO 存储Token
|
||
}
|
||
/**
|
||
* 查询Token
|
||
* 业务方自行实现
|
||
*
|
||
* @param token
|
||
*/
|
||
public VodAesTokenEntity getToken(String token) {
|
||
List<VodAesTokenEntity> vodAesTokenEntities = vodAesTokenDao.selectList(new LambdaQueryWrapper<VodAesTokenEntity>().eq(VodAesTokenEntity::getToken, token));
|
||
if(vodAesTokenEntities.size()!=1){
|
||
return null;
|
||
}else{
|
||
return vodAesTokenEntities.get(0);
|
||
}
|
||
}
|
||
/**
|
||
* 校验业务信息的有效性,业务方可自行实现
|
||
*
|
||
* @param infos
|
||
* @return
|
||
*/
|
||
private boolean validateInfo(String... infos) {
|
||
//TODO 校验信息的有效性,例如UID是否有效等
|
||
return true;
|
||
}
|
||
|
||
public static String encrypt(String value) {
|
||
try {
|
||
IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
|
||
SecretKeySpec skeySpec = new SecretKeySpec(ENCRYPT_KEY.getBytes("UTF-8"), "AES");
|
||
|
||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
|
||
|
||
byte[] encrypted = cipher.doFinal(value.getBytes());
|
||
|
||
// 使用 URL 安全的 Base64 编码
|
||
return Base64.getUrlEncoder().encodeToString(encrypted);
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public static String decrypt(String encrypted) {
|
||
try {
|
||
IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
|
||
SecretKeySpec skeySpec = new SecretKeySpec(ENCRYPT_KEY.getBytes("UTF-8"), "AES");
|
||
|
||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
|
||
|
||
// 使用 URL 安全的 Base64 解码
|
||
byte[] original = cipher.doFinal(Base64.getUrlDecoder().decode(encrypted));
|
||
|
||
return new String(original);
|
||
} catch (Exception ex) {
|
||
ex.printStackTrace();
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
|
||
/**
|
||
* AES加密生成Token
|
||
*
|
||
* @param encryptStr 要加密的字符串
|
||
* @param encryptKey 加密Key
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
// public String encrypt(String encryptStr, String encryptKey) throws Exception {
|
||
// IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
|
||
// SecretKeySpec skeySpec = new SecretKeySpec(encryptKey.getBytes("UTF-8"), "AES");
|
||
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||
// cipher.init(Cipher.ENCRYPT_MODE, skeySpec, e);
|
||
// byte[] encrypted = cipher.doFinal(encryptStr.getBytes());
|
||
// return Base64.encodeBase64String(encrypted);
|
||
// }
|
||
//
|
||
//
|
||
// /**
|
||
// * AES解密token
|
||
// *
|
||
// * @param encryptStr 解密字符串
|
||
// * @param decryptKey 解密Key
|
||
// * @return
|
||
// * @throws Exception
|
||
// */
|
||
// public String decrypt(String encryptStr, String decryptKey) throws Exception {
|
||
//
|
||
// IvParameterSpec e = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
|
||
// SecretKeySpec skeySpec = new SecretKeySpec(decryptKey.getBytes("UTF-8"), "AES");
|
||
// Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
|
||
// cipher.init(Cipher.DECRYPT_MODE, skeySpec, e);
|
||
//
|
||
// byte[] encryptByte = Base64.decodeBase64(encryptStr);
|
||
// byte[] decryptByte = cipher.doFinal(encryptByte);
|
||
// return new String(decryptByte);
|
||
// }
|
||
}
|
||
|