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){ + + } +}