使用Java构建Agora令牌服务器

视频聊天应用程序的安全性是很重要的。在Agora平台中,有一层安全性保护是以Token认证的形式出现的。本指南介绍了如何使用Java和Jersey来构建简单的微服务以生成Agora RTC令牌。

要求

  1. Apache TomcatIntelliJ IDEA IDEJersey框架Docker
  2. 对REST框架工作原理有基本了解。
  3. 理解Java类。
  4. Agora开发人员帐户

主要事项:

  1. 建立一个Jersey项目。
  2. 创建一个Hello World API。
  3. 生成Agora令牌。
  4. 生成Dockerize应用程序并将其部署在Ubuntu VM上。

创建项目

Archetype: Archetype是一个Maven项目模板工具包。

Artifact: 是一个文件,通常是一个被部署到 Maven 资源库的JAR文件。创建完的 Maven 能产生一个或多个 artifacts ,诸如编译JAR文件和JAR源文件。

jersey-quickstart-webapp 提供了一个基本的项目模板,对于初学者很有用并且足够强大。

打开 IntelliJ IDE ,然后单击“开始新项目”,我们将用 Maven 来创建新项目。单击 Archetype中的 创建,然后添加具有以下配置的 Archetype

Group Id: org.glassfish.jersey.archetypes
Artifact Id: jersey-quickstart-webapp
Version: 2.31

项目的最终配置如下所示:

项目创建完成后,我们将添加Tomcat服务器。如果还没有安装,则可以从Tomcat官方网站获取Tomcat 。安装完Tomcat后,你可以单击创建图标旁边的 添加配置

模板中 选择本地Tomcat服务器。最终配置如下所示:


完成应用配置并关闭配置窗口。你已经完成Jersey项目的创建并配置了Tomcat服务器。

Hello World API

在这个部分,你将会使用JSON和XML的输入、输出创建Hello World API。

导航到 pom.xml (包含所有Maven依赖项),取消注释JSON依赖项,然后添加JAVAX依赖项。你的依赖项应如下所示:

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>com.googlecode.json-simple</groupId>
            <artifactId>json-simple</artifactId>
            <version>1.1.1</version>
        </dependency>

    </dependencies>

编辑 src / main / webapp / index.JSP 并将以下代码添加到文件中:

<html>
<body>
    <h2>Agora Token Server</h2>
    <p><a href="webapi/myresource">Agora resource</a>
    <p>Visit <a href="https://agora.io/">Agora.io website</a>
    for more information on Agora!
</body>
</html>

现在编译项目。之后,IntelliJ会为你打开浏览器。默认情况下, index.JSP 文件都显示在浏览器中。浏览器应显示以下内容:

build-an-agora-token-server-using-java-5

单击 jersey资源,它将重新引导你到新的页面:

build-an-agora-token-server-using-java-6

注意 URL 。默认情况下, ServerletMapping 将所有内容映射到 */ webapi / 。你要 将其改为/ *。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>Agora Token Server</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.sandeep.agoratoken</param-value> <!-- Remember to replace this -->
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Agora Token Server</servlet-name>
        <url-pattern>/webapi/*</url-pattern>
    </servlet-mapping>
</web-app>

重新启动服务器。 webapi 已被删除。

怎么做到让它出现在网站上?

转到MyResource Java类。看起来就像这样:

build-an-agora-token-server-using-java-7

在这里,我们添加了 路径注释(@ PATH), 用于为MyResource类传入的HTTP请求定义一个URI匹配模式。

由于 Path annotation ,我们在URL中获得了“ myresource ” (即@ PATH(“ myresource”) )。我们为 getIt() 方法定义了 @ GET (第12行) ,它指定它将使用 GET HTTP方法.@ Produces annotation (第13行) 定义返回响应格式。

现在,添加 Agora 到项目中。

继续访问声网GitHub仓库,克隆整个仓库,然后复制并粘贴Media和RTM文件夹。文件结构应如下所示:

build-an-agora-token-server-using-java-9

注意: 找到每个文件更正软件包名称以避免发生错误。就我而言,它应该是 com.sandeep.agoratoken 而不是 io.agora。 通常情况下,IntelliJ帮你执行此操作。

单击右键将java文件命名为Agora、AgoraRepository和AgoraRTMRepository,然后删除MyResource文件后,3个新的Java类就创建完成了。

将以下代码粘贴到你的AgoraRepository中:

package com.sandeep.agoratoken; //make sure you change this

public class AgoraRepository {
    static String appId = "APP_ID";
    static String appCertificate ="APP_CERIFICATE";
    private String channelName;
    private int uid = 0; // By default 0
    private int expirationTimeInSeconds = 3600; // By default 3600
    private int role = 2; // By default subscriber
}

将以下代码粘贴到您的AgoraRTMRepository中

package com.sandeep.agoratoken;

public class AgoraRTMRepository {
    private static String appId = "APP_ID";
    private static String appCertificate = "APP_CERT";
    private String userId;
    private int expireTimestamp = 0;
}

现在,你需要获取器和设置器。

转到AgoraRepository类,然后根据操作系统输入命令:

* Ctrl + N for Linux and Windows users

* Cmd + N for Mac users

build-an-agora-token-server-using-java-10
上述命令的替换

你的文件应如下所示:

package com.sandeep.agoratoken;

public class AgoraRepository {
    static String appId = "APP_ID"; //replace app id
    static String appCertificate = "APP_CERT"; //replace app cert
    private String channelName;
    private int uid = 0;
    private int expirationTimeInSeconds = 3600;
    private int role = 2; // By default subscriber

    public static String getAppId() {
        return appId;
    }

    public static void setAppId(String appId) {
        AgoraRepository.appId = appId;
    }

    public static String getAppCertificate() {
        return appCertificate;
    }

    public static void setAppCertificate(String appCertificate) {
        AgoraRepository.appCertificate = appCertificate;
    }

    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public int getExpirationTimeInSeconds() {
        return expirationTimeInSeconds;
    }

    public void setExpirationTimeInSeconds(int expirationTimeInSeconds) {
        this.expirationTimeInSeconds = expirationTimeInSeconds;
    }

    public int getRole() {
        return role;
    }

    public void setRole(int role) {
        this.role = role;
    }


}

在AgoraRTMRepository中重复此步骤。你的文件现在应如下所示:

package com.sandeep.agoratoken;

public class AgoraRTMRepository {
    private static String appId = "APP_ID";
    private static String appCertificate = "APP_CERT";
    private String userId = "USER_ID";
    private int expireTimestamp = 0;

    public static String getAppId() {
        return appId;
    }

    public static String getAppCertificate() {
        return appCertificate;
    }

    public static void setAppCertificate(String appCertificate) {
        AgoraRTMRepository.appCertificate = appCertificate;
    }

    public String getUserId() {
        return userId;
    }


    public int getExpireTimestamp() {
        return expireTimestamp;
    }

    public static void setAppId(String appId) {
        AgoraRTMRepository.appId = appId;
    }
}

你会看到类似这样的内容,单击“获取器和设置器”,然后选择所有内容。这样Agora Token Server差不多就完成了 。

导入内容并定义 Token Server RTC POST Request:

package com.sandeep.agoratoken;

import com.sandeep.agoratoken.media.RtcTokenBuilder;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;

@Path("api")
public class Agora{

    @POST
    @Path("rtc")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTCToken(AgoraRepository resource) {
    
    }
 
}

初始化所有参数:

package com.sandeep.agoratoken;

import com.sandeep.agoratoken.media.RtcTokenBuilder;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;

@Path("api")
public class Agora{

    @POST
    @Path("rtc")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTCToken(AgoraRepository resource) {

        RtcTokenBuilder token = new RtcTokenBuilder();
        String channelName = resource.getChannelName();
        int expireTime = resource.getExpirationTimeInSeconds();
        RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
        int uid = resource.getUid();

    }

}

创建Token之前先检查一下,确保万无一失:

package com.sandeep.agoratoken;

import com.sandeep.agoratoken.media.RtcTokenBuilder;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;

@Path("api")
public class Agora{

    @POST
    @Path("rtc")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTCToken(AgoraRepository resource) {

        RtcTokenBuilder token = new RtcTokenBuilder();
        String channelName = resource.getChannelName();
        int expireTime = resource.getExpirationTimeInSeconds();
        RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
        int uid = resource.getUid();
        
        // check for null channelName
        if (channelName==null){
            JSONObject error=new JSONObject();
            error.put("error","Channel ID cannot be blank");
            return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
        }

        if(expireTime==0){
            expireTime = 3600;
        }

        if(resource.getRole()==1){
            role = RtcTokenBuilder.Role.Role_Publisher;
        }else if(resource.getRole()==0){
            role = RtcTokenBuilder.Role.Role_Attendee;
        }


    }

}

创建一个时间戳并生成令牌:

package com.sandeep.agoratoken;

import com.sandeep.agoratoken.media.RtcTokenBuilder;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;

@Path("api")
public class Agora{

    @POST
    @Path("rtc")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTCToken(AgoraRepository resource) {

        RtcTokenBuilder token = new RtcTokenBuilder();
        String channelName = resource.getChannelName();
        int expireTime = resource.getExpirationTimeInSeconds();
        RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
        int uid = resource.getUid();
        
        // check for null channelName
        if (channelName==null){
            JSONObject error=new JSONObject();
            error.put("error","Channel ID cannot be blank");
            return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
        }

        if(expireTime==0){
            expireTime = 3600;
        }

        if(resource.getRole()==1){
            role = RtcTokenBuilder.Role.Role_Publisher;
        }else if(resource.getRole()==0){
            role = RtcTokenBuilder.Role.Role_Attendee;
        }
      
        int timestamp = (int)(System.currentTimeMillis() / 1000 + expireTime);


        String result = token.buildTokenWithUid(resource.appId, resource.appCertificate,
                channelName, uid, role, timestamp);
        System.out.print(result);
        JSONObject jsondict = new JSONObject();
        jsondict.put("message",result);
        return jsondict;


    }

}

Agora Java RTC token server.创建完成! 现在就可以启动了

将以下代码添加到你的Agora类中:

@POST
@Path("rtm")
@Produces(MediaType.APPLICATION_JSON)
public Object getRTMToken(AgoraRTMRepository resource) throws Exception {

    String userId = resource.getUserId();

    if (userId==null){
        JSONObject error=new JSONObject();
        error.put("error","User ID cannot be blank");
        return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
    }

    RtmTokenBuilder token = new RtmTokenBuilder();
    String result = token.buildToken(resource.getAppId(), resource.getAppCertificate(), userId, Role.Rtm_User, resource.getExpireTimestamp());
    System.out.println(result);
    JSONObject jsondict = new JSONObject();
    jsondict.put("message",result);
    return jsondict;
}

最终代码应如下所示:

package com.sandeep.agoratoken;

import com.sandeep.agoratoken.media.RtcTokenBuilder;
import com.sandeep.agoratoken.rtm.RtmTokenBuilder;
import com.sandeep.agoratoken.rtm.RtmTokenBuilder.Role;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.simple.JSONObject;

@Path("api")
public class Agora{

    @POST
    @Path("rtc")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTCToken(AgoraRepository resource) {

        RtcTokenBuilder token = new RtcTokenBuilder();
        String channelName = resource.getChannelName();
        int expireTime = resource.getExpirationTimeInSeconds();
        RtcTokenBuilder.Role role = RtcTokenBuilder.Role.Role_Subscriber;
        int uid = resource.getUid();

        // check for null channelName
        if (channelName==null){
            JSONObject error=new JSONObject();
            error.put("error","Channel ID cannot be blank");
            return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
        }

        if(expireTime==0){
            expireTime = 3600;
        }

        if(resource.getRole()==1){
            role = RtcTokenBuilder.Role.Role_Publisher;
        }else if(resource.getRole()==0){
            role = RtcTokenBuilder.Role.Role_Attendee;
        }

        int timestamp = (int)(System.currentTimeMillis() / 1000 + expireTime);


        String result = token.buildTokenWithUid(resource.appId, resource.appCertificate,
                channelName, uid, role, timestamp);
        System.out.print(result);
        JSONObject jsondict = new JSONObject();
        jsondict.put("message",result);
        return jsondict;


    }

    @POST
    @Path("rtm")
    @Produces(MediaType.APPLICATION_JSON)
    public Object getRTMToken(AgoraRTMRepository resource) throws Exception {

        String userId = resource.getUserId();

        if (userId==null){
            JSONObject error=new JSONObject();
            error.put("error","User ID cannot be blank");
            return Response.status(Response.Status.BAD_REQUEST).entity(error).build();
        }

        RtmTokenBuilder token = new RtmTokenBuilder();
        String result = token.buildToken(resource.getAppId(), resource.getAppCertificate(), userId, Role.Rtm_User, resource.getExpireTimestamp());
        System.out.println(result);
        JSONObject jsondict = new JSONObject();
        jsondict.put("message",result);
        return jsondict;
    }

}

你以为这就大功告成了吗?不,我们还需要部署。

部署方式

首先,你需要创建一个 WAR文件。 从右侧切换栏打开Maven,然后单击Maven图标执行命令:

现在运行 mvn clean package

一两分钟就会生成一个WAR文件,你可以看到WAR文件的位置。

在你的存储库中创建一个Dockerfile,并将你的代码推送到GitHub。

FROM tomcat:9.0.37
MAINTAINER SaiSandeep

COPY target/agoratoken.war /usr/local/tomcat/webapps/ROOT.war

EXPOSE 8080

CMD ["catalina.sh", "run"]

创建一个Ubuntu VM。

运行以下命令在Linux上安装Docker:

sudo apt-get update

sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io

Mac和Windows用户可以从此Docker官方网站中获取可执行文件。

运行此命令以检查是否已安装Docker-> docker -v

将你的仓库克隆到VM。并运行以下命令:

nano src/main/java/com/sandeep/agoratoken/MyResourceRepository.java

填写你的APP_ID和APP_CERT。你就可以从Agora.io控制台获取APP_ID和APP_CERT。

build-an-agora-token-server-using-java-13

要构建Docker映像,请运行以下命令:

docker build -t agoratoken ./

OK,运行!

docker run -p 80:8080 agoratoken

检查API。


更多资源

有关Agora.io应用程序令牌的更多信息,请参阅《设置身份验证指南》《Agora高级指南:如何构建令牌(Go)》

Github库:AgoraToken参考代码

原文作者 Agora Superstar
原文链接https://www.agora.io/en/blog/building-an-agora-token-server-using-java/

推荐阅读
相关专栏
SDK 教程
164 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。