概述
在之前這篇博客《無插件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推流鑑權亦可使用這種方案。