概述
在之前这篇博客《无插件web直播解决方案》中,我汇总了一个可用的直播前后端解决方案。而这篇博客将针对该方案,讲述一种直播拉流鉴权方法。也就是一种验证用户是否有权限访问直播流地址的方法,可以用来防盗链。
就当是记录自己的想法了。
思路
用户在web端登陆成功后,Java服务端将用户的id、密码,当前时间等信息合并成一个字符串,使用RSA算法公钥加密该字符串,生成一个密文key。把这个密文key作为前端直播流地址的一个参数,发送给Nginx-rtmp服务器。Nginx-rtmp再将参数转发给Java后台的验证服务。验证通过则可正常播放。
可实现的功能
- 通过验证IP和用户身份,限制一个账号多处登陆。
- 防止盗链播放
- 加入日期的密文相当于24小时更新一次,可降低密文外泄危害
方案流程图
具体实现
1.加密解密的实现
主要用到了hutool这个第三方工具来简化加密解密代码。
maven引入hutool
<dependency>
<groupId>com.xiaoleilu</groupId>
<artifactId>hutool-all</artifactId>
<version>3.1.0</version>
</dependency>
随机生成RSA公钥和私钥
RSA rsa=new RSA();
rsa.getPrivateKeyBase64();
rsa.getPublicKeyBase64();
工具类的实现
import com.xiaoleilu.hutool.crypto.asymmetric.KeyType;
import com.xiaoleilu.hutool.crypto.asymmetric.RSA;
import com.xiaoleilu.hutool.util.CharsetUtil;
import com.xiaoleilu.hutool.util.HexUtil;
import com.xiaoleilu.hutool.util.StrUtil;
public class RSAUtils {
//加密
public static String encrypt(String words, String PublicKey) {
RSA rsa = new RSA(null, PublicKey);
String encryptWords = rsa.encryptStr(words, KeyType.PublicKey);
return encryptWords;
}
//解密
public static String decrypt(String encryptWords, String PrivateKey) {
RSA rsa = new RSA(PrivateKey, null);
byte[] encryptWordsByte = HexUtil.decodeHex(encryptWords);
byte[] decryptWordsByte = rsa.decrypt(encryptWordsByte, KeyType.PrivateKey);
String decryptWords = StrUtil.str(decryptWordsByte, CharsetUtil.CHARSET_UTF_8);
return decryptWords;
}
}
2.验证服务的实现
这个比较简单,进行获取url参数,用工具类解密密文,将信息与数据库做比较等操作即可。还可通过配合Nginx-rtmp的相关接口实现对用户同时登录IP数量的限制,防止获取一个密文即可无限盗链播放。
3.Nginx-rtmp配置修改(基于之前文章的修改)
在 on_play处添加Java验证服务的地址,Nginx-rtmp会在发送直播流前,访问这个地址进行验证,若验证成功该地址返回200,失败则返回401等异常状态码。参数key也会被转发给这个地址。
rtmp {
out_queue 1024;
out_cork 8;
max_streams 128;
timeout 15s;
drop_idle_publisher 15s;
log_interval 5s; #log模块在access.log中记录日志的间隔时间,对调试非常有用
log_size 1m; #log模块用来记录日志的缓冲区大小
server {
listen 1935;
server_name www.test.*; #用于虚拟主机名后缀通配
application myapp {
live on;
on_play http://localhost:8081/check; #Java验证服务的地址
...
另外,有一个特别重要的点需要注意。
Nginx-rtmp的默认url长度值过小,故url过长时会被截断。而RSA加密后的密文又很长。这个问题需要通过修改Nginx-rtmp的源代码来解决,即修改url参数长度最大值。
具体修改方法:
- 进入Nginx-rtmp源码目录,使用vim打开ngx_rtmp_cmd_module.h文件。
- 将下图中的值改为你需要的大小(默认大小为256)。
- 按照之前博客的方法重新编译Nginx+Nginx-rtmp
由于对Nginx-rtmp源码并不了解,网上中文资料也比较少,我在这个问题上耗费了大量时间。日志文件中还查不到任何错。最终在GitHub的issure上找到这个解决方法。
4.flv.js前端实现(基于之前文章的修改)
...
function startVideo() {
var _video = videoElement = document.getElementById('videoElement');
var temp = {
type: 'flv',
enableWorker: true,
isLive: true,
stashInitialSize: 128,
hasAudio: false,
hasVideo: true,
lazyLoad: false,
enableStashBuffer: false
};
temp["url"] = "http://127.0.0.1:81/live?port=1935&app=myapp&stream=mystream&key="+_data
var flvPlayer = flvjs.createPlayer(temp);
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
...
其中_data这个变量即为密文key。可由后端生成后,通过ajax获取。
5.总结
具体实现不难,难的是自己对配置Nginx不熟悉啊。。当遇到url被截断的问题后,便手足无措了。百度也搜不到解决方法,还好github有人提过相关问题。(果然我能遇到的问题,肯定有人也遇到过)
也可使用Nginx的auth_request模块实现nginx端鉴权控制,这种方法配置起来更灵活一些,但也麻烦,也不太熟悉Nginx就没用。
rtmp推流鉴权亦可使用这种方案。