GoLang을 사용하여 Agora 애플리케이션을 위한 토큰 서버 구축 방법

52554 단어 goagoraiosecurity
비디오 채팅 응용 프로그램의 안전성은 현재의 핫이슈이다.원격 작업과 가상 사건이 갈수록 많아지면서 안전성에 대한 수요도 증가할 것이다.
Agora 플랫폼에서 보안은 영패 인증 형식으로 나타납니다.모르는 사람에게 영패는 주어진 입력으로 생성된 동적 키를 사용합니다.Agora의 플랫폼은 영패를 사용하여 사용자를 인증합니다.
Agora는 RTC와 RTM SDK에 영패 보안을 제공합니다.이 안내서는 Golang과 Gin framework를 이용하여 간단한 마이크로서비스를 구축하여 Agora RTC와 RTM 영패를 생성하는 방법을 설명할 것이다.

선결 조건

  • Golang에 대한 기본적인 이해(필요한 최소 지식)
  • 웹 서버의 기능 이해(필요한 지식 최소)
  • Agora 개발자 계정(참조: How To Get Started with Agora
  • 프로젝트 설정


    우선, 터미널을 열어 프로젝트에 새 폴더를 만들고 cd를 넣습니다.
    mkdir agora-token-server
    cd agora-token-server
    
    프로젝트가 생성되었습니다. 프로젝트의 Go 모듈을 초기화합니다.
    go mod init agora-token-server
    
    마지막으로 Gin과 Agora 의존 항목을 추가하려면 go get 을 사용합니다.
    go get github.com/gin-gonic/gin
    go get github.com/AgoraIO-Community/go-tokenbuilder
    

    Gin 웹 서버 구축


    현재 항목이 설정되어 있습니다. 가장 좋아하는 코드 편집기에서 폴더를 열고 main.go 파일을 만듭니다.
    main.go 에서, 우리는 우선 우리의 가방을 설명하고 main 함수를 추가할 것이다.
    package main
    
    func main() {
    
    }
    
    다음은 가져오기Gin framework로 Gin 응용 프로그램을 만들고 간단한 GET 단점을 설정하여 정청으로 설정하고 localhost 포트8080에서 서비스할 것입니다.단순 노드에 대해 요청 컨텍스트를 가져오고 200 상태 헤더가 있는 JSON 응답을 반환하도록 설정합니다.
    package main
    
    import (
      "github.com/gin-gonic/gin"
    )
    
    func main() {
    
      api := gin.Default()
    
      api.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
          "message": "pong",
        })
      })
    
      api.Run(":8080") // listen and serve on localhost:8080
    }
    
    우리는 이미 우리의 서버를 테스트할 준비가 되어 있다.터미널 창으로 돌아가서 실행:
    go run main.go
    

    끝점을 테스트하려면 웹 브라우저를 열고 다음을 액세스하십시오.
    localhost:8080/ping
    
    서버가 예상대로 응답하는 것을 볼 수 있습니다.
    {"message":"pong"}
    
    엔드포인트 작업을 확인한 후 터미널 창으로 돌아가 키보드 명령ctrl c을 사용하여 프로세스를 종료합니다.

    아고라 영패 생성


    이제 Gin 서버 설정을 마쳤습니다. RTC와 RTM 토큰을 생성하는 기능을 추가할 예정입니다.
    영패를 생성하기 전에 AppIDAppCertificate를 추가해야 합니다.우리는 appIDappCertificate 범위의 문자열로 성명할 것입니다.이 가이드에서는 환경 변수를 사용하여 프로젝트 자격 증명을 저장하므로 읽어들여야 합니다.global 에서 환경 변수를 검색하려면 main() 를 사용합니다.os.LookupEnv 환경 변수의 문자열과 해당 변수의 부울 값을 반환합니다.우리는 환경 설정이 정확한지 확인하기 위해 다음 반환 값을 사용할 것이다.만약 그렇다면, 우리는 각각 환경 변수 값을 전역 os.LookupEnvappID 변수에 분배할 수 있다.
    package main
    
    import (
      "log"
      "os"
    
      "github.com/gin-gonic/gin"
    )
    
    var appID, appCertificate string
    
    func main() {
    
      appIDEnv, appIDExists := os.LookupEnv("APP_ID")
      appCertEnv, appCertExists := os.LookupEnv("APP_CERTIFICATE")
    
      if !appIDExists || !appCertExists {
        log.Fatal("FATAL ERROR: ENV not properly configured, check APP_ID and APP_CERTIFICATE")
      } else {
        appID = appIDEnv
        appCertificate = appCertEnv
      }
    
      api := gin.Default()
    
      api.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
          "message": "pong",
        })
      })
    
      api.Run(":8080")
    }
    
    다음에 우리는 세 개의 단점을 추가할 것이다. 하나는 RTC 영패, 다른 하나는 RTM 영패, 그리고 하나는 두 개의 영패를 되돌려준다.
    RTC 영패는 문자열과 정수를 기반으로 하는 UID를 구분하기 위해 채널 이름, UID, 사용자 역할, 영패 유형이 필요합니다. 마지막은 만료 시간입니다.RTM 끝에는 UID 및 만료 시간만 필요합니다.이중 영패 단점은 RTC 영패 단점과 같은 구조를 받아들여야 한다.
    api.GET("rtc/:channelName/:role/:tokentype/:uid/", getRtcToken)
    api.GET("rtm/:uid/", getRtmToken)
    api.GET("rte/:channelName/:role/:tokentype/:uid/", getBothTokens)
    
    중복 코드의 수를 최소화하기 위해 세 함수AppCertificate, getRtcToken, getRtmToken는 단독 함수(getBothTokens/parseRtcParams를 호출하여 각 단점에 전달되는 값을 검증하고 추출합니다.그리고 각 함수는 되돌아오는 값을 사용하여 영패를 생성하고 응답에서 JSON으로 되돌아온다parseRtmParams.
    RTC 영패는 두 가지 유형의 UID(body/uint를 사용하여 생성할 수 있으므로 함수(string포장Agora RTC Token Builder함수generateRtcToken/BuildTokenWithUserAccount를 사용합니다.
    다음은 영패 서버의 기본 템플릿입니다.우리는 모든 함수를 두루 훑어보고 빈칸을 채울 것이다.
    package main
    
    import (
      "log"
      "os"
    
      "github.com/AgoraIO-Community/go-tokenbuilder/rtctokenbuilder"
      "github.com/gin-gonic/gin"
    )
    
    var appID, appCertificate string
    
    func main() {
    
      appIDEnv, appIDExists := os.LookupEnv("APP_ID")
      appCertEnv, appCertExists := os.LookupEnv("APP_CERTIFICATE")
    
      if !appIDExists || !appCertExists {
        log.Fatal("FATAL ERROR: ENV not properly configured, check APP_ID and APP_CERTIFICATE")
      } else {
        appID = appIDEnv
        appCertificate = appCertEnv
      }
    
      api := gin.Default()
    
      api.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
          "message": "pong",
        })
      })
    
      api.GET("rtc/:channelName/:role/:tokenType/:uid/", getRtcToken)
      api.GET("rtm/:uid/", getRtmToken)
      api.GET("rte/:channelName/:role/:tokenType/:uid/", getBothTokens)
    
      api.Run(":8080")
    }
    
    func getRtcToken(c *gin.Context) {
    
    }
    
    func getRtmToken(c *gin.Context) {
    
    }
    
    func getBothTokens(c *gin.Context) {
    
    }
    
    func parseRtcParams(c *gin.Context) (channelName, tokentype, uidStr string, role rtctokenbuilder.Role, expireTimestamp uint32, err error) {
    
    }
    
    func parseRtmParams(c *gin.Context) (uidStr string, expireTimestamp uint32, err error) {
    
    }
    
    func generateRtcToken(channelName, uidStr, tokentype string, role rtctokenbuilder.Role, expireTimestamp uint32) (rtcToken string, err error) {
    
    }
    

    RTC 영패 구축


    우리는 BuildTokenWithUID부터 시작할 것이다.이 함수 인용getRtcToken, 호출gin.Context을 사용하면 후자는 필요한 값을 추출합니다.그리고 되돌아오는 값 호출 parseRtcParams 을 사용하여 영패 문자열을 생성합니다.우리는 과정 중에 아무런 문제가 없도록 일부 오류 검사도 포함할 것이다.마지막으로, 우리는 응답을 구축할 것이다.
    func getRtcToken(c *gin.Context) {
      log.Printf("rtc token\n")
      // get param values
      channelName, tokentype, uidStr, role, expireTimestamp, err := parseRtcParams(c)
    
      if err != nil {
        c.Error(err)
        c.AbortWithStatusJSON(400, gin.H{
          "message": "Error Generating RTC token: " + err.Error(),
          "status":  400,
        })
        return
      }
    
      rtcToken, tokenErr := generateRtcToken(channelName, uidStr, tokentype, role, expireTimestamp)
    
      if tokenErr != nil {
        log.Println(tokenErr) // token failed to generate
        c.Error(tokenErr)
        errMsg := "Error Generating RTC token - " + tokenErr.Error()
        c.AbortWithStatusJSON(400, gin.H{
          "status": 400,
          "error":  errMsg,
        })
      } else {
        log.Println("RTC Token generated")
        c.JSON(200, gin.H{
          "rtcToken": rtcToken,
        })
      }
    }
    
    다음은 우리 generateRtcToken 를 기입합시다.이 함수는 gin도 인용합니다.상하문, 우리는 그것을 사용하여 파라미터를 추출하고 되돌려 줄 것이다.parseRtcParams 또한 오류를 되돌려줍니다. 문제가 발생하면 오류 메시지를 되돌려줄 수 있습니다.
    
    func parseRtcParams(c *gin.Context) (channelName, tokentype, uidStr string, role rtctokenbuilder.Role, expireTimestamp uint32, err error) {
      // get param values
      channelName = c.Param("channelName")
      roleStr := c.Param("role")
      tokentype = c.Param("tokentype")
      uidStr = c.Param("uid")
      expireTime := c.DefaultQuery("expiry", "3600")
    
      if roleStr == "publisher" {
        role = rtctokenbuilder.RolePublisher
      } else {
        role = rtctokenbuilder.RoleSubscriber
      }
    
      expireTime64, parseErr := strconv.ParseUint(expireTime, 10, 64)
      if parseErr != nil {
        // if string conversion fails return an error
        err = fmt.Errorf("failed to parse expireTime: %s, causing error: %s", expireTime, parseErr)
      }
    
      // set timestamps
      expireTimeInSeconds := uint32(expireTime64)
      currentTimestamp := uint32(time.Now().UTC().Unix())
      expireTimestamp = currentTimestamp + expireTimeInSeconds
    
      return channelName, tokentype, uidStr, role, expireTimestamp, err
    }
    
    마지막으로, 우리는 parseRtcParams 함수를 채울 것이다.이 함수는 채널 이름, UID를 문자열, 영패 유형 generateRtcToken 또는 uid, 역할 및 만료 시간으로 사용합니다.
    이 값을 사용하면 이 함수는 영패 문자열을 생성하기 위해 적당한 Agora RTC Token Builder 함수(userAccount/BuildTokenWithUserAccount를 호출합니다.일단 영패 생성기 함수가 돌아오면, 우리는 먼저 오류를 검사하고, 오류가 없으면, 영패 문자열 값을 되돌려줍니다.
    func generateRtcToken(channelName, uidStr, tokentype string, role rtctokenbuilder.Role, expireTimestamp uint32) (rtcToken string, err error) {
    
      if tokentype == "userAccount" {
        log.Printf("Building Token with userAccount: %s\n", uidStr)
        rtcToken, err = rtctokenbuilder.BuildTokenWithUserAccount(appID, appCertificate, channelName, uidStr, role, expireTimestamp)
        return rtcToken, err
    
      } else if tokentype == "uid" {
        uid64, parseErr := strconv.ParseUint(uidStr, 10, 64)
        // check if conversion fails
        if parseErr != nil {
          err = fmt.Errorf("failed to parse uidStr: %s, to uint causing error: %s", uidStr, parseErr)
          return "", err
        }
    
        uid := uint32(uid64) // convert uid from uint64 to uint 32
        log.Printf("Building Token with uid: %d\n", uid)
        rtcToken, err = rtctokenbuilder.BuildTokenWithUID(appID, appCertificate, channelName, uid, role, expireTimestamp)
        return rtcToken, err
    
      } else {
        err = fmt.Errorf("failed to generate RTC token for Unknown Tokentype: %s", tokentype)
        log.Println(err)
        return "", err
      }
    }
    

    RTM 토큰 구축


    이어서 우리 계속 BuildTokenWithUID 합시다.위의 코드와 같이 getRtmToken 인용getRtmToken, 호출gin.Context을 사용하여 필요한 값을 추출하고 되돌아오는 값을 사용하여 RTM 영패를 생성합니다.여기서 차이점은 우리가 직접 아고라 RTM 영패 생성기를 호출하여 영패 String을 생성한다는 것이다.우리는 아무런 문제가 없도록 오류 검사를 포함하고, 마지막에 응답을 구축할 것입니다.
    func getRtmToken(c *gin.Context) {
      log.Printf("rtm token\n")
      // get param values
      uidStr, expireTimestamp, err := parseRtmParams(c)
    
      if err != nil {
        c.Error(err)
        c.AbortWithStatusJSON(400, gin.H{
          "message": "Error Generating RTC token: " + err.Error(),
          "status":  400,
        })
        return
      }
    
      rtmToken, tokenErr := rtmtokenbuilder.BuildToken(appID, appCertificate, uidStr, rtmtokenbuilder.RoleRtmUser, expireTimestamp)
    
      if tokenErr != nil {
        log.Println(err) // token failed to generate
        c.Error(err)
        errMsg := "Error Generating RTM token: " + tokenErr.Error()
        c.AbortWithStatusJSON(400, gin.H{
          "error":  errMsg,
          "status": 400,
        })
      } else {
        log.Println("RTM Token generated")
        c.JSON(200, gin.H{
          "rtmToken": rtmToken,
        })
      }
    }
    
    다음은 우리 parseRtmParams 를 기입합시다.이 함수는 parseRtmParams 를 인용한 다음 인자를 추출하고 되돌려줍니다.
    func parseRtmParams(c *gin.Context) (uidStr string, expireTimestamp uint32, err error) {
      // get param values
      uidStr = c.Param("uid")
      expireTime := c.DefaultQuery("expiry", "3600")
    
      expireTime64, parseErr := strconv.ParseUint(expireTime, 10, 64)
      if parseErr != nil {
        // if string conversion fails return an error
        err = fmt.Errorf("failed to parse expireTime: %s, causing error: %s", expireTime, parseErr)
      }
    
      // set timestamps
      expireTimeInSeconds := uint32(expireTime64)
      currentTimestamp := uint32(time.Now().UTC().Unix())
      expireTimestamp = currentTimestamp + expireTimeInSeconds
    
      // check if string conversion fails
      return uidStr, expireTimestamp, err
    }
    

    RTC 및 RTM 토큰 구축


    이제 단일 서버에서 RTC와 RTM 영패를 생성할 수 있습니다. 이 두 영패를 단일 요청에서 생성할 수 있도록 gin.Context 을 작성합니다.우리는 getBothTokens와 매우 비슷한 코드를 사용할 것이지만, 이번에는 RTM 영패를 포함할 것이다.
    func getBothTokens(c *gin.Context) {
      log.Printf("dual token\n")
      // get rtc param values
      channelName, tokentype, uidStr, role, expireTimestamp, rtcParamErr := parseRtcParams(c)
    
      if rtcParamErr != nil {
        c.Error(rtcParamErr)
        c.AbortWithStatusJSON(400, gin.H{
          "message": "Error Generating RTC token: " + rtcParamErr.Error(),
          "status":  400,
        })
        return
      }
      // generate the rtcToken
      rtcToken, rtcTokenErr := generateRtcToken(channelName, uidStr, tokentype, role, expireTimestamp)
      // generate rtmToken
      rtmToken, rtmTokenErr := rtmtokenbuilder.BuildToken(appID, appCertificate, uidStr, rtmtokenbuilder.RoleRtmUser, expireTimestamp)
    
      if rtcTokenErr != nil {
        log.Println(rtcTokenErr) // token failed to generate
        c.Error(rtcTokenErr)
        errMsg := "Error Generating RTC token - " + rtcTokenErr.Error()
        c.AbortWithStatusJSON(400, gin.H{
          "status": 400,
          "error":  errMsg,
        })
      } else if rtmTokenErr != nil {
        log.Println(rtmTokenErr) // token failed to generate
        c.Error(rtmTokenErr)
        errMsg := "Error Generating RTC token - " + rtmTokenErr.Error()
        c.AbortWithStatusJSON(400, gin.H{
          "status": 400,
          "error":  errMsg,
        })
      } else {
        log.Println("RTC Token generated")
        c.JSON(200, gin.H{
          "rtcToken": rtcToken,
          "rtmToken": rtmToken,
        })
      }
    
    }
    

    토큰 서버 테스트


    터미널 창으로 돌아가서 영패 서버를 실행합시다.
    run main.go
    
    서버 실례가 실행된 후에 우리는 단점 목록과 메시지를 볼 수 있습니다: getRtcToken.

    현재 저희 서버의 실례가 실행 중입니다. 웹 브라우저를 열고 테스트를 진행하겠습니다.이러한 테스트에 대해 우리는 각종 조회 파라미터를 생략하는 변체를 시도할 것이다.

    RTC 노드 테스트


    우리는 RTC 영패부터 시작할 것이다.
    http://localhost:8080/rtc/testing/publisher/userAccount/1234/
    http://localhost:8080/rtc/testing/publisher/uid/1234/
    
    단점은 채널에서 사용할 수 있는 영패를 생성합니다. Listening and serving HTTP on :8080 역할이 testingpublisherUID (문자열과 uint) 사용자가 사용합니다.
    {
      "rtcToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIADJRwbbO8J93uIDi4J305xNXA0A+pVDTPLPavzwsLW3uAZa8+ij4OObIgDqFTEDoOMyXwQAAQAwoDFfAgAwoDFfAwAwoDFfBAAwoDFf"
    }
    
    이 영패를 테스트하기 위해서 우리는 사용할 수 있다Agora 1:1 Web Demo.

    RTM 노드 테스트


    이제 RTM 토큰을 테스트합니다.
    http://localhost:8080/rtm/1234/
    
    끝점은 영패를 생성합니다. UID가 1234인 사용자는 이 영패를 사용하여 주어진 1234 RTM에 로그인할 수 있습니다.
    {
      "rtmToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIABSMH0fzaqy7sa0erk8u4Bp6FJ4sO1kQ/o6HCRECBRrzKPg45sAAAAAEAAjAkAEO+cyXwEA6APLozFf"
    }
    
    이 영패를 테스트하기 위해서 우리는 사용할 수 있다Agora RTM Tutorial Demo.

    더블 영패 단점 테스트


    우리는 이중 영패 단점을 사용하여 테스트를 완성할 것이다.
    http://localhost:8080/rte/testing/publisher/userAccount/1234/
    http://localhost:8080/rte/testing/publisher/uid/1234/
    
    끝점은 AppIDRTC 영패를 생성하고 사용자는 RTM UID (문자열 또는 uint) 및 1234 역할의 비디오 채널을 사용할 수 있습니다: testing.
    {
      "rtcToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIAD33wY6pO+xp6iBY8mbYz2YtOIiRoTTrzdIPF9DEFlSIwZa8+ij4OObIgAQ6e0EX+UyXwQAAQDvoTFfAgDvoTFfAwDvoTFfBADvoTFf",
      "rtmToken": "0062ec0d84c41c4442d88ba6f5a2beb828bIABbCwQgl2te3rk0MEDZ2xrPoalb37fFhTqmTIbGeWErWaPg45sAAAAAEAD1WwYBX+UyXwEA6APvoTFf"
    }
    
    영패를 테스트하기 위해서 우리는 Agora 1:1 Web Demo RTC 영패에 사용할 수 있고, Agora RTM Tutorial Demo RTM 영패에 사용할 수 있다.

    끝점을 테스트하면 터미널 창에 모든 요청이 표시됩니다.

    완성!


    이렇게 해서 우리는 끝났다!코드를 작성하지 않았거나 최종 제품을 함께 보기 싫은 경우 GitHub에 모든 코드를 업로드했습니다Agora Token Service.
    제 강좌를 읽는 데 시간을 주셔서 감사합니다. 만약 문제가 있으면 저에게 알려주십시오.만약 당신이 어떤 개선된 공간을 보게 된다면, 언제든지 환매 요청을 제출하세요!

    기타 리소스


    아고라 토큰에 대한 더 많은 정보.io 응용 프로그램은 Set up Authentication 안내서와 [Agora Advanced guide: How to build a Token]f(https://docs.agora.io/en/Video/token_server_go?platform=Go)(Go를 참조하십시오.
    방문도 요청합니다join the Agoira.io Developer Slack community.

    좋은 웹페이지 즐겨찾기