基于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推流鉴权亦可使用这种方案。

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