Oauth 2.0 谷歌OAuth2返回“;无效的授权”;-签署JWT问题

Oauth 2.0 谷歌OAuth2返回“;无效的授权”;-签署JWT问题,oauth-2.0,google-oauth,Oauth 2.0,Google Oauth,我有一个OAuth2Java客户机(用于服务器到服务器的应用程序),它试图创建一个JWT,然后使用私钥(从GoogleAPI控制台)进行签名——请参见以下页面。然而,GoogleOAuth2不断返回“无效授权” 以下是客户端代码: import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException;

我有一个OAuth2Java客户机(用于服务器到服务器的应用程序),它试图创建一个JWT,然后使用私钥(从GoogleAPI控制台)进行签名——请参见以下页面。然而,GoogleOAuth2不断返回“无效授权”

以下是客户端代码:

    import java.io.BufferedInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;

    import java.security.InvalidKeyException;
    import java.security.KeyFactory;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;

    import java.text.MessageFormat;

    import org.apache.commons.codec.binary.Base64;


    public class WebToken
    {  
      private String iss;
      private String prn;
      private String scope;
      private String aud;
      private long exp;
      private long iat;
      private String keystoreLoc;
      private String keyAlias;
      private String password;

      public WebToken(String iss, String prn, String scope, String aud, long exp, long iat, String p12file, String keyAlias, String password)
      {
        super();
        this.iss = iss;
        this.prn = prn;
        this.scope = scope;
        this.aud = aud;
        this.exp = exp;
        this.iat = iat;
        this.keystoreLoc = p12file;
        this.keyAlias = keyAlias;
        this.password = password;
      }

      public static String encodeBase64(byte[] rawData)
      {
        byte[] data = Base64.encodeBase64(rawData);

        return new String(data);
      }

      public String getToken()
        throws Exception
      {
        String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        //String header = "{\"alg\":\"RS256\"}";
        String claimTemplate = "'{'\"iss\": \"{0}\", \"prn\": \"{1}\", \"scope\": \"{2}\", \"aud\": \"{3}\", \"exp\": {4}, \"iat\": {5}'}'";

        StringBuffer token = new StringBuffer();

        //Encode the JWT Header and add it to our string to sign
        token.append(encodeBase64(header.getBytes("UTF-8")));

        //Separate with a period
        token.append(".");

        //Create the JWT Claims Object
        String[] claimArray = new String[6];
        claimArray[0] = this.iss;
        claimArray[1] = this.prn;
        claimArray[2] = this.scope;
        claimArray[3] = this.aud;
        claimArray[4] = "" + this.exp;
        claimArray[5] = "" + this.iat;

        MessageFormat claims = new MessageFormat(claimTemplate);
        String payload = claims.format(claimArray);
        print(payload);

        //Add the encoded claims object
        token.append(encodeBase64(payload.getBytes("UTF-8")));

        //Load the private key
        PrivateKey privateKey = getPrivateKey(keystoreLoc, password);
        byte[] sig = signData(token.toString().getBytes("UTF-8"), privateKey);
        String signedPayload = encodeBase64(sig);

        //Separate with a period
        token.append(".");

        //Add the encoded signature
        token.append(signedPayload);

        return token.toString();
      }

      private PrivateKey getPrivateKey(String keyFile, String password)
        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
      {
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        keystore.load(new FileInputStream(keyFile), password.toCharArray());
        PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray());

        return privateKey;
      }

      public byte[] signData(byte[] data, PrivateKey privateKey)
        throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
      {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
      }

      public static void print(String msg)
      {
        System.out.println(msg);
      }

      public static void main(String[] args)
        throws Exception
      {
        String iss = "????????@developer.gserviceaccount.com";
        String prn = "xxx@gmail.com";
        String scope = "https://www.googleapis.com/auth/urlshortener";
        String aud = "https://accounts.google.com/o/oauth2/token";
        long iat =  System.currentTimeMillis()/1000 - 60;
        long exp =  iat + 3600;
        String keystoreLoc = "D:\\OAuth2\\google_sURL\\pkey1.p12";
        String keyAlias = "privatekey";
        String pwd = "notasecret";

        WebToken jwt = new WebToken(iss, prn, scope, aud, exp, iat, keystoreLoc, keyAlias, pwd);
        String token = jwt.getToken();
        print(token);
        // urn:ietf:params:oauth:grant-type:jwt-bearer
        print("curl -vSs -X POST -d \"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + token + 
              "\" -k https://accounts.google.com/o/oauth2/token");
      }
}
然后使用curl获取访问令牌:curl-k-vSs-X POST-d“grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant type%3Ajwt承载和断言=”

知道怎么了吗

============================

最后我自己发现了问题:

1) 在JWT中,不要设置“prn”(但根据需要,您可能需要设置)

2) 使用“@developer.gserviceaccount.com”作为“iss”

以下是更新的代码:

    import java.io.FileInputStream;
    import java.io.IOException;

    import java.security.InvalidKeyException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;

    import java.text.MessageFormat;

    import org.apache.commons.codec.binary.Base64;


    public class WebToken
    {  
      private String iss;
      private String scope;
      private String aud;
      private long exp;
      private long iat;
      private String keystoreLoc;
      private String keyAlias;
      private String password;

      public WebToken(String iss, String scope, String aud, long exp, long iat, String p12file, String keyAlias, String password)
      {
        super();
        this.iss = iss;
        this.scope = scope;
        this.aud = aud;
        this.exp = exp;
        this.iat = iat;
        this.keystoreLoc = p12file;
        this.keyAlias = keyAlias;
        this.password = password;
      }

      /**
       * Performs base64-encoding of input bytes.
       *
       * @param rawData * Array of bytes to be encoded.
       * @return * The base64 encoded string representation of rawData.
       */
      public static String encodeBase64(byte[] rawData)
      {
        String data = Base64.encodeBase64URLSafeString(rawData);

        return data;
      }

      public String getToken()
        throws Exception
      {
        String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        String claimTemplate = "'{'\"iss\": \"{0}\", \"scope\": \"{1}\", \"aud\": \"{2}\", \"exp\": {3}, \"iat\": {4}'}'";
        StringBuffer token = new StringBuffer();

        //Encode the JWT Header and add it to our string to sign
        token.append(encodeBase64(header.getBytes("UTF-8")));

        //Separate with a period
        token.append(".");

        //Create the JWT Claims Object
        String[] claimArray = new String[6];
        claimArray[0] = this.iss;
        claimArray[1] = this.scope;
        claimArray[2] = this.aud;
        claimArray[3] = "" + this.exp;
        claimArray[4] = "" + this.iat;

        MessageFormat claims = new MessageFormat(claimTemplate);
        String payload = claims.format(claimArray);
        print(payload);

        //Add the encoded claims object
        token.append(encodeBase64(payload.getBytes("UTF-8")));

        //Load the private key
        PrivateKey privateKey = getPrivateKey(keystoreLoc, password);
        byte[] sig = signData(token.toString().getBytes("UTF-8"), privateKey);

        String signedPayload = encodeBase64(sig);

        //Separate with a period
        token.append(".");

        //Add the encoded signature
        token.append(signedPayload);

        return token.toString();
      }

      private PrivateKey getPrivateKey(String keyFile, String password)
        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
      {
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        keystore.load(new FileInputStream(keyFile), password.toCharArray());
        PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray());

        return privateKey;
      }

      public byte[] signData(byte[] data, PrivateKey privateKey)
        throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
      {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
      }

      public static void print(String msg)
      {
        System.out.println(msg);
      }

      public static void main(String[] args)
        throws Exception
      {
        String iss = "<client id email>@developer.gserviceaccount.com";
        String scope = "https://www.googleapis.com/auth/urlshortener";
        String aud = "https://accounts.google.com/o/oauth2/token";
        long iat =  (System.currentTimeMillis()/1000)-60;
        long exp =  iat + 3600;
        String keystoreLoc = "<privatekey>.p12";
        String keyAlias = "privatekey";
        String pwd = "notasecret";

        WebToken jwt = new WebToken(iss, scope, aud, exp, iat, keystoreLoc, keyAlias, pwd);
        String token = jwt.getToken();
        print(token);
        print("\\curl\\curl -vSs -X POST -H \"Content-Type: application/x-www-form-urlencoded\"" + 
              " -d \"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + token +    
              "\" -k https://accounts.google.com/o/oauth2/token");
      }
    }
import java.io.FileInputStream;
导入java.io.IOException;
导入java.security.InvalidKeyException;
导入java.security.KeyStore;
导入java.security.KeyStoreException;
导入java.security.NoSuchAlgorithmException;
导入java.security.PrivateKey;
导入java.security.Signature;
导入java.security.SignatureException;
导入java.security.UnrecoverableKeyException;
导入java.security.cert.CertificateException;
导入java.text.MessageFormat;
导入org.apache.commons.codec.binary.Base64;
公共类WebToken
{  
专用字符串iss;
私有字符串范围;
私人字符串aud;
私人长期出口;
私人长途电话;
私有字符串keystoreLoc;
私有字符串密钥别名;
私有字符串密码;
公共WebToken(字符串iss、字符串范围、字符串aud、长exp、长iat、字符串P12文件、字符串keyAlias、字符串密码)
{
超级();
this.iss=iss;
this.scope=范围;
this.aud=aud;
this.exp=exp;
this.iat=iat;
this.keystoreLoc=p12文件;
this.keyalis=keyalis;
this.password=密码;
}
/**
*对输入字节执行base64编码。
*
*@param rawData*要编码的字节数组。
*@return*原始数据的base64编码字符串表示形式。
*/
公共静态字符串encodeBase64(字节[]rawData)
{
String data=Base64.encodebase64urlsafetstring(rawData);
返回数据;
}
公共字符串getToken()
抛出异常
{
字符串头=“{\“alg\”:\“RS256\”,\“typ\”:\“JWT\”}”;
String claimTemplate=“{'\'iss\':\“{0}\”、\'scope\':\“{1}\”、\'aud\':\“{2}\”、\'exp\':{3}、\'iat\':{4}';
StringBuffer令牌=新的StringBuffer();
//对JWT头进行编码,并将其添加到字符串中进行签名
token.append(encodeBase64(header.getBytes(“UTF-8”));
//以句号分开
标记。附加(“.”);
//创建JWT声明对象
String[]clairray=新字符串[6];
Clairerray[0]=this.iss;
索偿权[1]=此范围;
索偿权[2]=本澳元;
Claimerray[3]=“this.exp;
Claimerray[4]=“this.iat;
MessageFormat索赔=新的MessageFormat(索赔模板);
字符串有效载荷=claims.format(claimerray);
打印(有效载荷);
//添加编码的索赔对象
token.append(encodeBase64(payload.getBytes(“UTF-8”));
//加载私钥
PrivateKey PrivateKey=getPrivateKey(keystoreLoc,密码);
byte[]sig=signData(token.toString().getBytes(“UTF-8”),privateKey);
String signedPayload=encodeBase64(sig);
//以句号分开
标记。附加(“.”);
//添加编码的签名
token.append(signedPayload);
返回token.toString();
}
private PrivateKey getPrivateKey(字符串密钥文件、字符串密码)
抛出KeyStoreException、IOException、NoSuchAlgorithmException、CertificateException、UnrecoverableKeyException
{
KeyStore KeyStore=KeyStore.getInstance(“PKCS12”);
load(新文件输入流(keyFile),password.toCharArray());
PrivateKey PrivateKey=(PrivateKey)keystore.getKey(keyalis,password.toCharArray());
返回私钥;
}
公共字节[]signData(字节[]数据,私钥私钥)
抛出InvalidKeyException、SignatureException、NoSuchAlgorithmException
{
Signature=Signature.getInstance(“SHA256withRSA”);
signature.initSign(私钥);
签名。更新(数据);
返回签名。sign();
}
公共静态无效打印(字符串消息)
{
System.out.println(msg);
}
公共静态void main(字符串[]args)
抛出异常
{
字符串iss=“@developer.gserviceaccount.com”;
字符串范围=”https://www.googleapis.com/auth/urlshortener";
字符串aud=”https://accounts.google.com/o/oauth2/token";
长iat=(System.currentTimeMillis()/1000)-60;
长期有效期=iat+3600;
字符串keystoreLoc=“.p12”;
字符串keyalis=“privatekey”;
字符串pwd=“notasecret”;
WebToken jwt=新的WebToken(iss、范围、aud、exp、iat、KeystoreOC、keyAlias、pwd);
字符串标记=jwt.getToken();
打印(代币);
打印(“\\curl\\curl-vSs-X POST-H\”内容类型:application/X-www-form-urlencoded\”+
“-d\”授权类型=urn%3aitef%3aparms%3oauth%3aagrant类型%3Ajwt承载与断言=“+token+
“\”-khttps://accounts.g
    import java.io.FileInputStream;
    import java.io.IOException;

    import java.security.InvalidKeyException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.Signature;
    import java.security.SignatureException;
    import java.security.UnrecoverableKeyException;
    import java.security.cert.CertificateException;

    import java.text.MessageFormat;

    import org.apache.commons.codec.binary.Base64;


    public class WebToken
    {  
      private String iss;
      private String scope;
      private String aud;
      private long exp;
      private long iat;
      private String keystoreLoc;
      private String keyAlias;
      private String password;

      public WebToken(String iss, String scope, String aud, long exp, long iat, String p12file, String keyAlias, String password)
      {
        super();
        this.iss = iss;
        this.scope = scope;
        this.aud = aud;
        this.exp = exp;
        this.iat = iat;
        this.keystoreLoc = p12file;
        this.keyAlias = keyAlias;
        this.password = password;
      }

      /**
       * Performs base64-encoding of input bytes.
       *
       * @param rawData * Array of bytes to be encoded.
       * @return * The base64 encoded string representation of rawData.
       */
      public static String encodeBase64(byte[] rawData)
      {
        String data = Base64.encodeBase64URLSafeString(rawData);

        return data;
      }

      public String getToken()
        throws Exception
      {
        String header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        String claimTemplate = "'{'\"iss\": \"{0}\", \"scope\": \"{1}\", \"aud\": \"{2}\", \"exp\": {3}, \"iat\": {4}'}'";
        StringBuffer token = new StringBuffer();

        //Encode the JWT Header and add it to our string to sign
        token.append(encodeBase64(header.getBytes("UTF-8")));

        //Separate with a period
        token.append(".");

        //Create the JWT Claims Object
        String[] claimArray = new String[6];
        claimArray[0] = this.iss;
        claimArray[1] = this.scope;
        claimArray[2] = this.aud;
        claimArray[3] = "" + this.exp;
        claimArray[4] = "" + this.iat;

        MessageFormat claims = new MessageFormat(claimTemplate);
        String payload = claims.format(claimArray);
        print(payload);

        //Add the encoded claims object
        token.append(encodeBase64(payload.getBytes("UTF-8")));

        //Load the private key
        PrivateKey privateKey = getPrivateKey(keystoreLoc, password);
        byte[] sig = signData(token.toString().getBytes("UTF-8"), privateKey);

        String signedPayload = encodeBase64(sig);

        //Separate with a period
        token.append(".");

        //Add the encoded signature
        token.append(signedPayload);

        return token.toString();
      }

      private PrivateKey getPrivateKey(String keyFile, String password)
        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
      {
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        keystore.load(new FileInputStream(keyFile), password.toCharArray());
        PrivateKey privateKey = (PrivateKey) keystore.getKey(keyAlias, password.toCharArray());

        return privateKey;
      }

      public byte[] signData(byte[] data, PrivateKey privateKey)
        throws InvalidKeyException, SignatureException, NoSuchAlgorithmException
      {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
      }

      public static void print(String msg)
      {
        System.out.println(msg);
      }

      public static void main(String[] args)
        throws Exception
      {
        String iss = "<client id email>@developer.gserviceaccount.com";
        String scope = "https://www.googleapis.com/auth/urlshortener";
        String aud = "https://accounts.google.com/o/oauth2/token";
        long iat =  (System.currentTimeMillis()/1000)-60;
        long exp =  iat + 3600;
        String keystoreLoc = "<privatekey>.p12";
        String keyAlias = "privatekey";
        String pwd = "notasecret";

        WebToken jwt = new WebToken(iss, scope, aud, exp, iat, keystoreLoc, keyAlias, pwd);
        String token = jwt.getToken();
        print(token);
        print("\\curl\\curl -vSs -X POST -H \"Content-Type: application/x-www-form-urlencoded\"" + 
              " -d \"grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=" + token +    
              "\" -k https://accounts.google.com/o/oauth2/token");
      }
    }