虎牙开放平台文档

统一鉴权说明

虎牙小程序API以及开放API都通过JWT方式进行接入验签操作。

1.JWT的结构:

JWT通过以下三部分组成:

Header Payload Signature 通过英文点号"."拼接成 Header.Payload.Signature

样例如下:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTYxODgzOTEsImV4cCI6MTU1NjE4ODk5MSwiYXBwSWQiOiJ4eHh4eHh4eHh4eHgifQ.DFdsMFu_VzPkUUS1eu_Kwyzvc6vSQ-x_HI3wEut72cU

2.各字段说明

3.1 Header

Header部分是一个JSON字符串,描述 JWT 的元数据:

{ "alg": "HS256", "typ": "JWT" }
  • 1.alg属性表示签名的算法,字符串类型,默认是HS256(HMACSHA256);
  • 2.typ属性表示token的类型,字符串类型,统一为JWT;
  • 3.将Header对应的Json字符串进行base64UrlEncode(header)(可在jwt.io验证),转换后的字符串为:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

3.2 Payload

Payload部分也是一个JSON字符串,用来存放实际需要传递的数据。 以下是虎牙开放API约定的必填字段:

{ "iat":1556188391, "exp":1556188991, "appId":"xxxxxxxxxxxx" }
  • 1.iat属性表示当前时间的unix时间戳(秒),整型;
  • 2.exp属性表示过期时间的unix时间戳(秒),整型,通常设置10分钟有效,即exp=iat+600,注意不少于当前时间且不超过当前时间60分钟;
  • 3.appId属性为开发者申请的开发者账号(点此查看),字符串类型;
  • 4.将Payload对应的Json字符串进行base64UrlEncode(payload)(可在jwt.io验证),转换后的字符串为:
eyJpYXQiOjE1NTYxODgzOTEsImV4cCI6MTU1NjE4ODk5MSwiYXBwSWQiOiJ4eHh4eHh4eHh4eHgifQ
  • 注意,JWT的数据传递默认是不加密的,请不要把秘密信息放在这个部分。

3.3 Signature

Signature部分是对前两部分(Header和Payload)的签名,防止数据篡改。

  • 1.首先需要指定一个密钥appSecret,这个密钥对应的是开发者申请的appId的secret(点此查看)。
  • 2.使用HMACSHA256算法计算出签名,完整的签名生成如下(可在jwt.io验证)(例子中的secret为123456):
HMACSHA256( base64UrlEncode(Header) + "." + base64UrlEncode(Payload), secret) //!注意:secret不需要base64UrlEncode
  • 3.将计算出的签名进行base64UrlEncode(可在jwt.io验证),转换后的字符串为:
DFdsMFu_VzPkUUS1eu_Kwyzvc6vSQ-x_HI3wEut72cU

3.4 JWT串(token)

最后把Header、Payload、Signature三部分拼成字符串,每个部分之间用"."(点)分隔,上面例子对应的JWT串(sToken)是:

拼成:Header.Payload.Signature eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTYxODgzOTEsImV4cCI6MTU1NjE4ODk5MSwiYXBwSWQiOiJ4eHh4eHh4eHh4eHgifQ.DFdsMFu_VzPkUUS1eu_Kwyzvc6vSQ-x_HI3wEut72cU

3.JWT官方网站上有各种语言的类库。

4.JWT加解密DEMO

本示例用JAVA语言写了一个小程序token的加解密的demo。具体的可在代码仓库中查看详细代码。

代码示例

package hyext.token.examples; import java.util.Date; import java.util.HashMap; import java.util.Map; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; /** * 小程序Token加解密demo */ public class ExtToken { /** * 签名生成 * @param appId 小程序开发者ID(成为开发者后,https://ext.huya.com可查) * @param secret 小程序开发者密钥(成为开发者后,https://ext.huya.com可查) * @param extUuid 小程序ID(成为开发者后,https://ext.huya.com可查) * @param profileId 主播unionId * @param second 签名有效时间(秒) * @return */ public static String genToken(String appId, String secret, String extUuid, String profileId, int second) { //获取时间戳(毫秒) long currentTimeMillis = System.currentTimeMillis(); long expireTimeMillis = System.currentTimeMillis() + second * 60 * 1000; //超时时间 Date iat = new Date(currentTimeMillis); Date exp = new Date(expireTimeMillis); try { Map<String, Object> header = new HashMap<String, Object>(); header.put("alg", "HS256"); header.put("typ", "JWT"); //生成JWT凭证 Algorithm algorithm = Algorithm.HMAC256(secret); //开发者密钥 String sToken = JWT.create() .withHeader(header) //JWT声明 .withIssuedAt(iat) //jwt凭证生成时间 .withExpiresAt(exp) //jwt凭证超时时间 .withClaim("appId", appId) //开发者ID .withClaim("extUuid", extUuid) //小程序ID .withClaim("creator", "DEV") //创建者(token生成方:SYS平台,DEV开发者) .withClaim("profileId", profileId) //开发者ID .sign(algorithm); return sToken; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 签名解密 * @param token 小程序签名串 * @param sceret 小程序开发者密钥(成为开发者后,https://ext.huya.com可查) * @return */ public static Map<String, Claim> parseToken(String token, String sceret) { DecodedJWT jwt = null; try { JWTVerifier verifier = JWT.require(Algorithm.HMAC256(sceret)).build(); jwt = verifier.verify(token); return jwt.getClaims(); } catch (Exception e) { e.printStackTrace(); return null; } } public static void main(String[] args) { String appId = "testAppId"; String extUuid = "testExtUuid"; String sceret = "testSecret"; String profileId = "testProfileId"; String token = genToken(appId, sceret, extUuid, profileId,86400); // 生成签名 System.out.println("token:" + token); Map<String, Claim> claims = parseToken(token, sceret); // 签名解密 System.out.println("claims appId :" + claims.get("appId").asString()); System.out.println("claims extUuid :" + claims.get("extUuid").asString()); System.out.println("claims profileId :" + claims.get("profileId").asString()); System.out.println("claims creator :" + claims.get("creator").asString()); } }