基於Nginx-rtmp+Java的直播拉流鑑權方案

概述

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章