多协议、性能稳定、丰富API的流媒体服务器软件
如何采用服务端API对rtmp流的连接请求进行访问控制?
下面有两个例子详细描述了如何采用服务端API对RTMP流的连接请求进行访问控制。

1. 用url参数传递用户名和密码,用文本文件存储用户名和密码


下面的代码例子展现了如何使用服务端API对RTMP流媒体播放请求进行访问控制,在这个例子中使用了一个基于文件的username/password认证方式。

package com.wowza.wms.plugin.collection.module;

import java.io.*;
import java.util.*;

import com.wowza.util.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.application.*;
import com.wowza.wms.authentication.*;
import com.wowza.wms.authentication.file.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.util.*;
import com.wowza.wms.vhost.*;

public class ModuleOnConnectAuthenticate2 extends ModuleBase
{ 
	public static final String AUTHPASSWORDFILEPATH = "${com.wowza.wms.context.VHostConfigHome}/conf/connect.password";
	private File passwordFile = null;
	private String usernamePasswordProviderClass = null;

	public void onAppStart(IApplicationInstance appInstance)
	{
		WMSProperties props = appInstance.getProperties();
				
		String passwordFileStr = props.getPropertyStr("rtmpAuthenticateFile", AUTHPASSWORDFILEPATH);
		this.usernamePasswordProviderClass = props.getPropertyStr("usernamePasswordProviderClass", this.usernamePasswordProviderClass);
		if (passwordFileStr != null)
		{
			Map<String, String> envMap = new HashMap<String, String>();
			
			IVHost vhost = appInstance.getVHost();
			envMap.put("com.wowza.wms.context.VHost", vhost.getName());
			envMap.put("com.wowza.wms.context.VHostConfigHome", vhost.getHomePath());
			envMap.put("com.wowza.wms.context.Application", appInstance.getApplication().getName());
			envMap.put("com.wowza.wms.context.ApplicationInstance", appInstance.getName());

			passwordFileStr = SystemUtils.expandEnvironmentVariables(passwordFileStr, envMap);
			passwordFile = new File(passwordFileStr);
		}
		
		if (passwordFile != null)
			getLogger().info("ModuleOnConnectAuthenticate: Authorization password file: "+passwordFile.getAbsolutePath());
		if (usernamePasswordProviderClass != null)
			getLogger().info("ModuleOnConnectAuthenticate: Authorization password class: "+usernamePasswordProviderClass);
	}

public void onConnect(IClient client, RequestFunction function, AMFDataList params)
{
	boolean isAuthenticated = false;
	
	String username = null;
	String password = null;
	
	try
	{
		while(true)
		{
			getLogger().info("size: " + params.size());
			
			String[] auth = client.getQueryStr().split("&");
			
			username = auth[0];
			password = auth[1];
				
				if (username == null || password == null)
					break;
								
				IAuthenticateUsernamePasswordProvider filePtr = null;
				if (usernamePasswordProviderClass != null)
					filePtr = AuthenticationUtils.createUsernamePasswordProvider(usernamePasswordProviderClass);
				else if (passwordFile != null)
					filePtr = AuthenticationPasswordFiles.getInstance().getPasswordFile(passwordFile);
				
				if (filePtr == null)
					break;

				filePtr.setClient(client);

				String userPassword = filePtr.getPassword(username);
				if (userPassword == null)
					break;

				if (!userPassword.equals(password))
					break;
				
				isAuthenticated = true;
				break;
			}
		}
		catch(Exception e)
		{
			getLogger().error("ModuleOnConnectAuthenticate.onConnect: "+e.toString());
			isAuthenticated = false;
		}
		
		if (!isAuthenticated)
			client.rejectConnection("Authentication Failed["+client.getClientId()+"]: "+username);
		else
			client.acceptConnection();
	}
}
		
编译后的模块包含在Wowza Modules 集合中。 下载并解开压缩包,将/lib/wms-plugin-collection.jar文件拷贝到Wowza /lib 文件夹下。然后重启Wowza Streaming Engine。

这个模块的使用方法
  1. 在[install-dir]/conf文件夹下创建一个文本文件,命名为connect.password,在每个新的一行添加一个用户名和密码(用空格分割开):

    [install-dir]/conf/connect.password:
    user1 pass1
    user2 pass2
    		  
  2. 将下面的模块添加到需要认证的应用的Application.xml文件的模块列表中:

    <Module> 
    <Name>moduleOnConnectAuthenticate2</Name> 
    <Description>ModuleOnConnectAuthenticate2</Description> 
    <Class>com.wowza.wms.plugin.collection.module.ModuleOnConnectAuthenticate2</Class> 
    </Module>
    			


2. 用url参数传递用户名和密码,用Mysql数据库存储用户名和密码



这个例子使用MySQL数据存储用户名和密码。

  1. 下载官方的JDBC driver for MySQL.

  2. 解压缩下载包后,将mysql-connector-java-5.0.5-bin.jar 拷贝到Wowza的安装路径的[install-dir]/lib下。

    服务端Java代码类似如下:
    package com.mycompany.wms.dbtest;
    
    import java.sql.*;
    
    import com.wowza.wms.application.*;
    import com.wowza.wms.amf.*;
    import com.wowza.wms.client.*;
    import com.wowza.wms.module.*;
    import com.wowza.wms.request.*;
    
    public class DBTest extends ModuleBase 
    {
    	public void onAppStart(IApplicationInstance appInstance)
    	{
    		// preload the driver class
    		try 
    		{
    			Class.forName("com.mysql.jdbc.Driver").newInstance(); 
    		} 
    		catch (Exception e) 
    		{ 
    			getLogger().error("Error loading: com.mysql.jdbc.Driver: "+e.toString());
    		} 
    	}
    
    	public void onConnect(IClient client, RequestFunction function, AMFDataList params) 
    	{
    		
    		String userName = getParamString(params, PARAM1);
    		String password = getParamString(params, PARAM2);
    
    		
    		Connection conn = null;
    		try 
    		{
    			conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
    
    			Statement stmt = null;
    			ResultSet rs = null;
    
    			try 
    			{
    				stmt = conn.createStatement();
    				rs = stmt.executeQuery("SELECT count(*) as userCount FROM users where username = '"+userName+"' and password = '"+password+"'");
    				if (rs.next() == true)
    				{
    				    if (rs.getInt("userCount") > 0)
    					{
    						client.acceptConnection();
    					}
    				}
    
    			} 
    			catch (SQLException sqlEx) 
    			{
    				getLogger().error("sqlexecuteException: " + sqlEx.toString());
    			} 
    			finally 
    			{
    				// it is a good idea to release
    				// resources in a finally{} block
    				// in reverse-order of their creation
    				// if they are no-longer needed
    
    				if (rs != null) 
    				{
    					try 
    					{
    						rs.close();
    					} 
    					catch (SQLException sqlEx) 
    					{
    
    						rs = null;
    					}
    				}
    
    				if (stmt != null) 
    				{
    					try 
    					{
    						stmt.close();
    					} 
    					catch (SQLException sqlEx) 
    					{
    						stmt = null;
    					}
    				}
    			}
    
    			conn.close();
    		} 
    		catch (SQLException ex) 
    		{
    			// handle any errors
    			System.out.println("SQLException: " + ex.getMessage());
    			System.out.println("SQLState: " + ex.getSQLState());
    			System.out.println("VendorError: " + ex.getErrorCode());
    		}
    
    		getLogger().info("onConnect: " + client.getClientId());
    	}
    
    	static public void onConnectAccept(IClient client) 
    	{
    		getLogger().info("onConnectAccept: " + client.getClientId());
    	}
    
    	static public void onConnectReject(IClient client) 
    	{
    		getLogger().info("onConnectReject: " + client.getClientId());
    	}
    
    	static public void onDisconnect(IClient client) 
    	{
    		getLogger().info("onDisconnect: " + client.getClientId());
    	}
    
    }
    		    
  3. 编辑Application.xml文件,在<Modules>列表中添加这个模块,然后将Connections/AutoAccept 设置为 false.