From 00b9f96dd130b1e293ed05e21b54b92be0bbd4b9 Mon Sep 17 00:00:00 2001
From: wangjinlei <751475802@qq.com>
Date: Thu, 18 Jul 2024 13:29:22 +0800
Subject: [PATCH] =?UTF-8?q?vod=E6=99=AE=E9=80=9A=E5=8A=A0=E5=AF=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 6 +-
.../com/peanut/common/utils/PlayToken.java | 167 ++++++++++++++++++
.../com/peanut/common/utils/SpdbUtil.java | 56 ++++++
.../modules/common/dao/VodAesTokenDao.java | 9 +
.../CourseCatalogueChapterVideoEntity.java | 2 +
.../common/entity/VodAesTokenEntity.java | 17 ++
.../controller/CourseController.java | 21 +++
.../sys/controller/VodAliController.java | 20 +++
8 files changed, 297 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/peanut/common/utils/PlayToken.java
create mode 100644 src/main/java/com/peanut/modules/common/dao/VodAesTokenDao.java
create mode 100644 src/main/java/com/peanut/modules/common/entity/VodAesTokenEntity.java
create mode 100644 src/main/java/com/peanut/modules/sys/controller/VodAliController.java
diff --git a/pom.xml b/pom.xml
index f805dfc1..5f73bcb9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -185,7 +185,11 @@
poi-ooxml-schemas
3.17
-
+
+ com.aliyun
+ sts20150401
+ 1.1.4
+
com.aspose.words
aspose-words
diff --git a/src/main/java/com/peanut/common/utils/PlayToken.java b/src/main/java/com/peanut/common/utils/PlayToken.java
new file mode 100644
index 00000000..6b6b04bf
--- /dev/null
+++ b/src/main/java/com/peanut/common/utils/PlayToken.java
@@ -0,0 +1,167 @@
+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 org.apache.commons.codec.binary.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, ENCRYPT_KEY); //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,ENCRYPT_KEY); //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 vodAesTokenEntities = vodAesTokenDao.selectList(new LambdaQueryWrapper().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;
+ }
+ /**
+ * 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);
+ }
+}
+
diff --git a/src/main/java/com/peanut/common/utils/SpdbUtil.java b/src/main/java/com/peanut/common/utils/SpdbUtil.java
index 00530312..368e7d39 100644
--- a/src/main/java/com/peanut/common/utils/SpdbUtil.java
+++ b/src/main/java/com/peanut/common/utils/SpdbUtil.java
@@ -5,6 +5,13 @@ import com.aliyun.teautil.models.RuntimeOptions;
import com.aliyun.vod20170321.Client;
import com.aliyun.vod20170321.models.GetVideoPlayAuthRequest;
import com.aliyun.vod20170321.models.GetVideoPlayAuthResponse;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.IClientProfile;
+import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
+import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
//import org.bytedeco.javacv.FFmpegFrameGrabber;
//import org.bytedeco.javacv.FrameGrabber;
@@ -59,4 +66,53 @@ public class SpdbUtil {
}
}
+
+
+
+
+ public static AssumeRoleResponse assumeRole() throws ClientException {
+ try {
+
+ String accessKeyId = "LTAI5tC9d38msYxw6RSEwJJR";
+
+ String accessKeySecret = "njJxkvrwBmbMfGyhAFeyjthodnwt58";
+
+ String roleArn = "acs:ram::1604740137891907:role/vodrole";
+
+ String roleSessionName = "testsession";
+
+ String policy = "{\n" +
+ " \"Version\": \"1\",\n" +
+ " \"Statement\": [\n" +
+ " {\n" +
+ " \"Action\": \"vod:*\",\n" +
+ " \"Resource\": \"*\",\n" +
+ " \"Effect\": \"Allow\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+ //构造default profile(参数留空,无需添加Region ID)
+ /*
+ 说明:当设置SysEndpoint为sts.aliyuncs.com时,regionId可填可不填;反之,regionId必填,根据使用的服务区域填写,例如:cn-shanghai
+ 详情参考STS各地域的Endpoint。
+ */
+ IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
+ //用profile构造client
+ DefaultAcsClient client = new DefaultAcsClient(profile);
+ // 创建一个 AssumeRoleRequest 并设置请求参数
+ final AssumeRoleRequest request = new AssumeRoleRequest();
+// request.setSysEndpoint("sts.aliyuncs.com");
+// request.setSysMethod(MethodType.POST);
+ request.setRoleArn(roleArn);
+ request.setRoleSessionName(roleSessionName);
+ request.setPolicy(policy);
+ request.setRegionId("cn-shanghai");
+ // 发起请求,并得到response
+ final AssumeRoleResponse response = client.getAcsResponse(request);
+ return response;
+ } catch (ClientException e) {
+ throw e;
+ }
+ }
+
}
diff --git a/src/main/java/com/peanut/modules/common/dao/VodAesTokenDao.java b/src/main/java/com/peanut/modules/common/dao/VodAesTokenDao.java
new file mode 100644
index 00000000..c1098b3a
--- /dev/null
+++ b/src/main/java/com/peanut/modules/common/dao/VodAesTokenDao.java
@@ -0,0 +1,9 @@
+package com.peanut.modules.common.dao;
+
+import com.github.yulichang.base.MPJBaseMapper;
+import com.peanut.modules.common.entity.VodAesTokenEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface VodAesTokenDao extends MPJBaseMapper {
+}
diff --git a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java
index 331005a9..7c9b0486 100644
--- a/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java
+++ b/src/main/java/com/peanut/modules/common/entity/CourseCatalogueChapterVideoEntity.java
@@ -36,4 +36,6 @@ public class CourseCatalogueChapterVideoEntity {
private UserCourseVideoPositionEntity userCourseVideoPositionEntity;
@TableField(exist = false)
private String videoUrl;
+ @TableField(exist = false)
+ private String Mp4Url;
}
diff --git a/src/main/java/com/peanut/modules/common/entity/VodAesTokenEntity.java b/src/main/java/com/peanut/modules/common/entity/VodAesTokenEntity.java
new file mode 100644
index 00000000..3890021e
--- /dev/null
+++ b/src/main/java/com/peanut/modules/common/entity/VodAesTokenEntity.java
@@ -0,0 +1,17 @@
+package com.peanut.modules.common.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("vod_aes_token")
+public class VodAesTokenEntity {
+
+ @TableId
+ private Integer id;
+
+ private String token;
+
+ private Integer useCount;
+}
diff --git a/src/main/java/com/peanut/modules/sociology/controller/CourseController.java b/src/main/java/com/peanut/modules/sociology/controller/CourseController.java
index 53745233..c9fdcb24 100644
--- a/src/main/java/com/peanut/modules/sociology/controller/CourseController.java
+++ b/src/main/java/com/peanut/modules/sociology/controller/CourseController.java
@@ -1,8 +1,10 @@
package com.peanut.modules.sociology.controller;
import com.aliyun.vod20170321.models.*;
+import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.peanut.common.utils.PlayToken;
import com.peanut.common.utils.R;
import com.peanut.common.utils.ShiroUtils;
import com.peanut.common.utils.SpdbUtil;
@@ -14,6 +16,7 @@ import com.peanut.modules.master.service.SysCourseDirectService;
import com.peanut.modules.sociology.service.CourseCatalogueChapterService;
import com.peanut.modules.sociology.service.CourseService;
import com.peanut.modules.sociology.service.CourseSociologyService;
+import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
@@ -42,6 +45,8 @@ public class CourseController {
@Autowired
private UserCourseStudyingDao userCourseStudyingDao;
+ @Autowired
+ private PlayToken playToken;
/**
* 获取用户最近学习课程列表
@@ -193,6 +198,22 @@ public class CourseController {
return courseCatalogueChapterVideoService.checkVideo(video);
}
+ @RequestMapping("/mytt")
+ public R mytt() throws Exception {
+ String s = playToken.generateToken();
+ System.out.println(s);
+ boolean b = playToken.validateToken(s);
+ System.out.println(b);
+ return R.ok();
+ }
+
+ @RequestMapping("/ttt")
+ @SneakyThrows
+ public R ttt(){
+ AssumeRoleResponse assumeRoleResponse = SpdbUtil.assumeRole();
+ return R.ok().put("result",assumeRoleResponse);
+ }
+
@RequestMapping("/getMyCourse")
public R getMyCourse(@RequestBody Map map){
List courses = courseService.getMyCourse(map.get("type"));
diff --git a/src/main/java/com/peanut/modules/sys/controller/VodAliController.java b/src/main/java/com/peanut/modules/sys/controller/VodAliController.java
new file mode 100644
index 00000000..6834189d
--- /dev/null
+++ b/src/main/java/com/peanut/modules/sys/controller/VodAliController.java
@@ -0,0 +1,20 @@
+package com.peanut.modules.sys.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping("/sys/vodAli")
+public class VodAliController {
+
+
+ @RequestMapping("/vodAliVideoRe")
+ public void vodAliVideoRe(@RequestBody Map map){
+
+ }
+}