在 Java 中创建 JSON Web 令牌

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20002372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 22:15:53  来源:igfitidea点击:

Creating JSON Web Token in Java

javajsongoogle-oauthjwt

提问by prathamesh_mb

I am trying to create a JSON Web Token in order to use it for making refresh token call with Google Analytics API access. I have taken service account approach.

我正在尝试创建一个 JSON Web 令牌,以便使用它通过 Google Analytics API 访问进行刷新令牌调用。我采取了服务帐户的方法。

As per this approach I need to :

按照这种方法,我需要:

  1. Create Service Account
  2. Add the Email Address created for the Analytics app with Google Analytics account.
  3. Download the priavte key file(.p12)
  4. Use this priavate key and email address for constructing JWT which will be subsequently used for making HTTP POST call to google auth server in order to get refresh token.
  1. 创建服务帐户
  2. 使用 Google Analytics 帐户添加为 Analytics 应用程序创建的电子邮件地址。
  3. 下载私有密钥文件(.p12)
  4. 使用此私有密钥和电子邮件地址构建 JWT,随后将用于对 google auth 服务器进行 HTTP POST 调用以获取刷新令牌。

I am not sure whether my approach of creating JWT is correct or not. The sample available as JWT_Handler.javaon the Google Code site talks about creating JWT with claim part and request payload only with header and signature part missing. This is confusing with googles guidelines for creating JWT for refresh token where the JWT involves three parts :

我不确定我创建 JWT 的方法是否正确。JWT_Handler.java谷歌代码站点上提供的示例讨论了创建带有声明部分和请求有效负载的 JWT,仅缺少标头和签名部分。这与为刷新令牌创建 JWT 的 googles 指南混淆,其中 JWT 涉及三个部分:

  1. JWT Header
  2. JWT Claim
  3. Signature
  1. JWT 标头
  2. JWT 声明
  3. 签名

All the three parts are Base64Url encoded. I tried following code :

这三个部分都是 Base64Url 编码的。我尝试了以下代码:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Calendar;
import java.util.Enumeration;

import com.google.api.client.util.Base64;
import com.google.gson.JsonObject;
public class TestJWT {

private final static Charset UTF8_CHARSET = Charset.forName("UTF-8");
private static KeyStore myStore = null;
private static FileInputStream in_cert = null;
public static void main(String[] args) {
    PrivateKey privateKey = null;       
    try {
        in_cert = new FileInputStream(
                "D://Google Analytics//ClientLogin//Analytics//%$%%$%$%-privatekey.p12");

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }       
    try {
        myStore = KeyStore.getInstance("PKCS12");
        myStore.load(in_cert, "notasecret".toCharArray());
        String alias = "";       
        Enumeration objEnumeration = myStore.aliases();
        while (objEnumeration.hasMoreElements() == true) {
            alias = (String) objEnumeration.nextElement();              
            privateKey = (PrivateKey) myStore.getKey(alias,
                    "notasecret".toCharArray());
        }
    } catch (Exception e1) {
        e1.printStackTrace();
    }

    JsonObject header = new JsonObject();
    header.addProperty("alg", "RS256");
    header.addProperty("typ", "JWT");

    Calendar cal = Calendar.getInstance();      
    cal.set(1970, 01, 01);      
    String iat = Long.toString((System.currentTimeMillis() - cal.getTimeInMillis())/1000);
    String exp = Long.toString((System.currentTimeMillis() - cal.getTimeInMillis())/1000 + 60000L);

    JsonObject claim = new JsonObject();
    claim.addProperty("iss", "$$%$^%&^!%@#[email protected]");
    claim.addProperty("scope", "https://www.googleapis.com/auth/devstorage.readonly");
    claim.addProperty("aud", "https://accounts.google.com/o/oauth2/token");
    claim.addProperty("access_type", "offline");
    claim.addProperty("exp", exp);
    claim.addProperty("iat", iat);


    System.out.println("Header : " + header);
    String headerStr = header.toString();
    System.out.println("claim : " + claim);
    String claimStr = claim.toString();


    try {

        byte[] headerArr = headerStr.getBytes(UTF8_CHARSET);
        System.out.println(Base64.encodeBase64String(headerArr));

        byte[] claimArr = claimStr.getBytes(UTF8_CHARSET);
        System.out.println(Base64.encodeBase64String(claimArr));

        String inputStr = Base64.encodeBase64String(headerArr) + "." + Base64.encodeBase64String(claimArr);

        System.out.println("Input String : " + inputStr);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(inputStr.getBytes(UTF8_CHARSET));
        System.out.println("Sign : " + signature.sign());

        System.out.println("Base64url encoded sign : " + Base64.encodeBase64String(signature.sign()));

        System.out.println("Final JWT : " + Base64.encodeBase64String(headerArr) + "." + Base64.encodeBase64String(claimArr) + "." + Base64.encodeBase64String(signature.sign()));

    } catch (Exception e) {
        e.printStackTrace();
    }
}

}

回答by aeijdenberg

Prathamesh, is this the same question as your other post? (Making Refresh Token Request In Java With JWT through a stand alone application - Not a Web App)

Prathamesh,这和你的其他帖子有同样的问题吗?(通过独立应用程序使用 JWT 在 Java 中发出刷新令牌请求 - 不是 Web 应用程序

To clarify, signing a JWT using the P12 file will let you get an access token (not a refresh token). That's OK, because an access token is what you need to make a subsequent API call.

澄清一下,使用 P12 文件签署 JWT 将使您获得访问令牌(而不是刷新令牌)。没关系,因为访问令牌是您进行后续 API 调用所需要的。

I strongly suggesting using Google's Java client library to construct the JWT and do the signing, of which you already pasted a good sample for in the other post:

我强烈建议使用 Google 的 Java 客户端库来构建 JWT 并进行签名,您已经在另一篇文章中粘贴了一个很好的示例:

GoogleCredential credentialGA = new GoogleCredential.Builder().setTransport(httpTransport)
        .setJsonFactory(JSON_FACTORY)
        .setServiceAccountId("$#$@#$#$#[email protected]")
        .setServiceAccountScopes(Collections.singleton(AnalyticsScopes.ANALYTICS_READONLY))
        .setServiceAccountPrivateKeyFromP12File(new File("$#$#$%$%$%$-privatekey.p12"))
        .build();
this.analytics = new Analytics.Builder(httpTransport, JSON_FACTORY, credentialGA).setApplicationName("Demo App").build();

Is there a specific reason you don't want to use the client library? It will take care of creating the JWT, signing it, sending it, buildng the service requests, adding authorization headers, refreshing the access token when it expires etc etc.

您是否有不想使用客户端库的特定原因?它将负责创建 JWT、对其进行签名、发送、构建服务请求、添加授权标头、在访问令牌过期时刷新访问令牌等。