功能介绍
1、当需要观众登录机构的用户系统,验证通过后才能进入直播观看页时,可使用外部授权。验证观众是否可观看由机构实现,验证通过后打开的观看页面由保利威实现。
2、机构后台针对通过验证的观众,打开直播观看页时URL需带上指定的参数,经过直播系统验证请求合法后,直播系统会调用客户在后台设置的自定义授权验证接口,进行接口授权验证,两次验证通过,才能进入直播观看页,并且接口返回的观众账号具有唯一性,即同一个账号不能在两个地方同时登录,较早登录的账号会被踢出。
1、Secretkey:用于校验签名的生成。
2、自定义URL:用于外部授权验证的API接口。
3、跳转地址:观众直接访问Polyv观看页,会跳转到该地址;若跳转地址为空,则显示默认提示页。
展示效果
http://demo.polyv.net/chenwb/open.php
外部授权流程详解
1、在自定义URL处填写用户的授权验证API接口,需要完整的不带参数的url地址(不能是localhost等本地服务器地址,且不能带 ? 号),如:http://myWebsite.com/auth
2、在请求保利威视直播观看页时需带上userid(用户ID,仅支持英文大小写、数字和下划线)、ts(当前时间的毫秒级时间戳)和sign(用于校验的签名,生成规则是secretkey + userid + secretkey + ts进行MD5加密),如https://live.polyv.cn/watch/125527?userid=6b3a43&ts=1498547407000&sign=dd9dc9e42ad7c0204398e925a4ee0f46
3、直播系统会对字符串secretkey+userid+secretkey+ts进行MD5加密后与用户提交的sign参数的值做比较判断是否合法。一次成功请求后,该链接将失效(sign只能成功使用一次)。如果合法,直播系统将调用用户的api接口,并把userid(用户ID)、ts(当前时间的毫秒级时间戳)、channelId(频道号)和token(用于校验的签名)四个参数通过GET请求传给用户。如果不合法,则给出错误提示。
4、用户API接口获取userid、ts和token参数后,进行签名验证。如果验证通过,则将学员相关信息(详参“用户系统返回观众信息json说明”)返回给直播系统。
5、直播系统接收用户API接口返回的数据,如果验证成功,则进入到保利威视直播观看页,聊天区将显示学员的昵称和头像。如果验证失败,则给出错误提示。
交互图如下
参数描述
请求观看页所带参数
用户将以下的参数提交给直播的观看页,(例如:https://live.polyv.cn/watch/125527?userid=test&ts=1565948760108&sign=b0b6eb22b6fa5e5684873052c27a6cef)
直播系统会对sign 进行验证,判断是否合法,一次成功请求后,该链接将失效(sign只能成功使用一次)
观看页请求观众信息接口参数
观看页请求用户在后台设置的自定义URL获取观众信息,以下为请求所带的参数
用户系统返回观众信息响应参数描述
响应示例
成功示例
{
"status":1,
"userid":"2qwerty",
"nickname":"testNick",
"actor":"paul",
"actorFColor":"#123123",
"actorBgColor":"#FFFFFF",
"param4":"param4test",
"avatar":"http://live.polyv.net/assets/images/avatars/9avatar.jpg"
}
异常示例
{
"status":0,
"errorUrl":"http://test.com"
}
代码示例(JAVA)
注:LiveSignUtil属于直播SDK,如不使用直播SDK可使用以下第三点中的“MD5签名方法”。
1、用户系统生成观看链接
public static void main(String[] args) {
//TODO 设置频道号
String channelId = "2275495";
//TODO 设置externalKey
String secret = "";
//根据实际情况设置userid
String userid = "sadboy";
String ts = String.valueOf(System.currentTimeMillis());
String url = "https://live.polyv.cn/watch/"+channelId;
String signText = secret+ userid +secret+ts;
try {
String sign = LiveSignUtil.md5Hex(signText);
url += "?userid="+userid+"&ts="+ts+"&sign="+sign;
log.info(url);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
2、用户服务器校验polyv直播系统回调
@Slf4j
@Controller
@RequestMapping(value = "/polyv")
public class PolyvController {
//TODO 修改secretKey
private static final String secret = "******";
@GetMapping("external")
@ResponseBody
public Map<String, Object> external(String channelId,String userid, Long ts, String token) {
Assert.assertNotBlack(userid);
Assert.assertNotBlack(token);
Assert.assertNotNull(ts);
HashMap<String, Object> map = new HashMap<>();
long timeMillis = System.currentTimeMillis();
long diffTime = Math.abs(timeMillis - ts);
//1、时间戳判断
if (diffTime > 5 * 60 * 1000) {
log.error("时间戳验证错误");
map.put("status", 0);
//抛出异常时,如果设置errorUrl,则会跳转到 errorUrl ,如果未返回 errorUrl,则先查询 外部授权参数
// externalRedirectUri,externalRedirectUri不为空则跳转externalRedirectUri地址,externalRedirectUri为空则跳转保利威默认页面
map.put("errorUrl", "https://www.polyv.net");
return map;
}
//2、签名判断
String signText = secret + userid + secret + ts;
String sign = null;
try {
sign = LiveSignUtil.md5Hex(signText);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (sign == null || !sign.equals(token)) {
log.error("签名验证错误");
map.put("status", 0);
//抛出异常时,如果设置errorUrl,则会跳转到 errorUrl ,如果未返回 errorUrl,则先查询 外部授权参数
// externalRedirectUri,externalRedirectUri不为空则跳转externalRedirectUri地址,externalRedirectUri为空则跳转保利威默认页面
map.put("errorUrl", "https://www.polyv.net");
return map;
}
//TODO 业务逻辑处理,后续需根据具体需求进行数据库操作
//3、正常返回
map.put("status", 1);
map.put("userid", userid);
map.put("nickname", "保利威测试用户");
map.put("marqueeName", "保利威测试跑马灯");
map.put("actor", "学生");
map.put("actorFColor", "#2469f3");
map.put("actorBgColor", null);
map.put("param4", null);
map.put("param5", null);
map.put("avatar", "https://help.polyv.net/favicon.ico");
return map;
}
}
3、MD5签名方法
/**
* 对字符串做MD5加密,返回加密后的字符串。
* @param text 待加密的字符串。
* @return 加密后的字符串。
* @throws NoSuchAlgorithmException 签名异常
* @throws UnsupportedEncodingException 编码异常
*/
public static String md5Hex(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] inputByteArray = text.getBytes(LiveConstant.UTF8);
messageDigest.update(inputByteArray);
byte[] resultByteArray = messageDigest.digest();
return byteArrayToHex(resultByteArray).toLowerCase();
}
/**
* 将字节数组换成成16进制的字符串
* @param byteArray 字节
* @return 字符串
*/
public static String byteArrayToHex(byte[] byteArray) {
// 初始化一个字符数组用来存放每个16进制字符
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
// new一个字符数组,这个就是用来组成结果字符串的(一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方))
char[] resultCharArray = new char[byteArray.length * 2];
// 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去
int index = 0;
for (byte b : byteArray) {
resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
resultCharArray[index++] = hexDigits[b & 0xf];
}
// 字符数组组合成字符串返回
return new String(resultCharArray);
}
代码示例(PHP)
<?php
header("Content-type:application/json;charset=UTF-8"); //媒体格式类型为JSON数据格式
$secretkey = "aDrOt0Cpy8";
$userid = isset($_GET["userid"]) ? $_GET["userid"] : "";
$ts = isset($_GET["ts"]) ? $_GET["ts"] : "";
$channelId = isset($_GET["channelId"]) ? $_GET["channelId"] : "";
$token = isset($_GET["token"]) ? $_GET["token"] : "";
$sign = md5($secretkey . $userid . $secretkey . $ts);
//用户进行授权验证,返回对应的数据(json格式)
if ($sign == $token) {
//验证正确
$array1 = array(
"status" => 1, //返回状态
"userid" => $userid, //学员唯一标识
"nickname" => "保利威", //学员昵称
"marqueeName" => "polyv", //自定义跑马灯字段
"avatar" => "http://live.polyv.net/assets/images/avatars/9avatar.jpg", //学员头像
"actor" => "VIP", // 学员头衔,可以不传递
"actorFColor" => "#5C96E5", // 学员头衔字体颜色,可以不传递
"actorBgColor" => "#FFFFFF" // 学员头衔背景颜色,可以不传递
);
$json1 = json_encode($array1);
echo $json1;
} else {
//验证错误
$array0 = array(
"status" => 0,
"errorUrl" => "http://xxx.xx.xxxx/error.html", //验证错误跳转的自定义页面
);
$json0 = json_encode($array0);
echo $json0;
}
注意事项
1、要保证自定义验证接口返回的userid的唯一性,当多个观众使用同一个userid进入观看页时,较早登录的观众会被后面登录的观众踢出,观看页会提示 "帐号在另外的地方登录,您将被退出观看。如下图:
2、自定义验证接口需要填写完整的URL地址,且不能是localhost等本地服务器地址。
3、自定义验证接口返回给直播系统的数据格式是json格式。
4、同时传入了nickname和marqueeName,在观看日志中,marqueeName将作为用户昵称的统计字段。
错误提示
1、user not found:请求自定义验证接口错误,或者接口返回的格式不对。
2、invalid sign:签名错误,sign的生成规则是secretkey+userid+secretkey+ts进行MD5加密。
3、sign expired:签名过期,每一个sign只能使用一次,使用后需重新生成。