2016-03-02 224 views
2

我的Java應用程序正在接收JWT。我有PEM格式的公鑰:如何使用PEM格式的RSA公鑰解碼JWT令牌?

-----BEGIN PUBLIC KEY----- 
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAixn0CGu8/M4txn4pdp8K 
m8RQfVa+cHX25/a5sPmzP49u7YlQsRvtOexzgdwDcfUJm3hHMZcbZBtrHKsS8q4Q 
QtGQioyVml8EaLuFNFYisaIEldVyRbXFG54FNp03vSU9ImS/cOiM9swo+1w5JgWO 
F9efy7JO40LA9E7lv64COUYjFhrn+HRZuKoblL19+Sj49FyXexAUS29UM9PfIdY6 
ar1FA8cxzPqW7EkXZ0Mua3IzNnYcjMvUL9TJwoLAAz9S1Tv4Is5jupy9UXkuJ4r8 
Jx9DqI3Q3ur0VekYSd5tnTI4K+no9ABCFVv7+6Q45Ec2eB0xMwlqI+phcGhGMVCX 
1QIDAQAB 
-----END PUBLIC KEY----- 

我知道我可以使用一個JwtConsumer驗證和解碼JWT:

JwtConsumer jwtConsumer = new JwtConsumerBuilder() 
    .setRequireExpirationTime() 
    .setVerificationKey(publicKey) // what do I pass here? 
    .build(); 

但如何將我的PEM文件分割成可以理解的格式.setVerificationKey()

回答

2

隨着v0.5.0存在爲應付PEM編碼的公鑰,RsaKeyUtil.fromPemEncoded(String pem)一些公共事業的支持,這可能會爲你簡化一些事情。您也可以直接從JwtClaims對象獲取聲明值,這也可能會簡化。以下是您稍作修改的示例:

String jwt = "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6Ik1DaGFtYmU0IiwiZXhwIjoxNDU2OTEwODgzLCJzY29wZSI6WyJvcGVuaWQiLCJwMnAiLCJociIsImRhcyIsIm1lIl0sImNsaWVudF9pZCI6Im1vYmlsZSIsImp0aSI6ImNZcHBMYXltVzlmNXFBZk4ifQ.QqZI9vV8IznTjN-GtUSCri9-6HH6Yl1Oae6K8-d2yjQ4fysF5d3wStdL2kMazl7xeqbtSIsw-F5Aol9eHdGAu54b9IyBEM_QIasy0lnT8xFk0Zi36NJ-7yhl_89f6SB6TGimM59xUvzXxuAw3FzWM6TbiptInrCL2TXkhS69Gng-ANPeiSITUX5A1TDInssds6ZoSb7IOUMtxPGfrbO9sBjx8aJlIu9igkqk4OX5xBmxLp3icoo98I5v9Wt_Huu7eWKBfOskMSEav4X_m5_phbAZJ_F8nWRmcxk6O7hCQdawzegnhMxP2IPIhwlWRNX_8WxkNErq2fJgdazDf8pS_Q"; 

    // read public key from a file or config or something 
    String publicKeyPEM = 
      "-----BEGIN PUBLIC KEY-----\n" + 
      "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAixn0CGu8/M4txn4pdp8K\n" + 
      "m8RQfVa+cHX25/a5sPmzP49u7YlQsRvtOexzgdwDcfUJm3hHMZcbZBtrHKsS8q4Q\n" + 
      "QtGQioyVml8EaLuFNFYisaIEldVyRbXFG54FNp03vSU9ImS/cOiM9swo+1w5JgWO\n" + 
      "F9efy7JO40LA9E7lv64COUYjFhrn+HRZuKoblL19+Sj49FyXexAUS29UM9PfIdY6\n" + 
      "ar1FA8cxzPqW7EkXZ0Mua3IzNnYcjMvUL9TJwoLAAz9S1Tv4Is5jupy9UXkuJ4r8\n" + 
      "Jx9DqI3Q3ur0VekYSd5tnTI4K+no9ABCFVv7+6Q45Ec2eB0xMwlqI+phcGhGMVCX\n" + 
      "1QIDAQAB\n" + 
      "-----END PUBLIC KEY-----"; 

    RsaKeyUtil rsaKeyUtil = new RsaKeyUtil(); 
    PublicKey publicKey = rsaKeyUtil.fromPemEncoded(publicKeyPEM); 

    // create a JWT consumer 
    JwtConsumer jwtConsumer = new JwtConsumerBuilder() 
      .setRequireExpirationTime() 
      .setVerificationKey(publicKey) 
      .build(); 

    // validate and decode the jwt 
    JwtClaims jwtDecoded = jwtConsumer.processToClaims(jwt); 
    String username = jwtDecoded.getStringClaimValue("username"); // "MChambe4" 

    // ensure the required scope is claimed 
    String requiredScope = "das"; 
    List<String> scopes = jwtDecoded.getStringListClaimValue("scope"); 
    if (!scopes.stream().anyMatch(scope -> scope.equals(requiredScope))) { 
     throw new Exception("Required scope is not claimed: " + requiredScope); 
    } 
} 
3

我不得不先將Base64解碼爲其組成字節的公鑰,然後以X509格式對字節進行編碼。

這裏是在這個完整的例子,以及如何閱讀從解碼JWT一些聲稱:

package jwt; 

import org.jose4j.jwt.JwtClaims; 
import org.jose4j.jwt.consumer.JwtConsumer; 
import org.jose4j.jwt.consumer.JwtConsumerBuilder; 
import sun.misc.BASE64Decoder; 

import java.security.KeyFactory; 
import java.security.PublicKey; 
import java.security.spec.X509EncodedKeySpec; 
import java.util.ArrayList; 
import java.util.Map; 

public class JwtExample { 

    public void decodeJwt(String jwt) throws Exception { 

     // read public key from a file or config or something 
     String publicKeyPEM = 
      "-----BEGIN PUBLIC KEY-----\n" + 
       "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAixn0CGu8/M4txn4pdp8K\n" + 
       "m8RQfVa+cHX25/a5sPmzP49u7YlQsRvtOexzgdwDcfUJm3hHMZcbZBtrHKsS8q4Q\n" + 
       "QtGQioyVml8EaLuFNFYisaIEldVyRbXFG54FNp03vSU9ImS/cOiM9swo+1w5JgWO\n" + 
       "F9efy7JO40LA9E7lv64COUYjFhrn+HRZuKoblL19+Sj49FyXexAUS29UM9PfIdY6\n" + 
       "ar1FA8cxzPqW7EkXZ0Mua3IzNnYcjMvUL9TJwoLAAz9S1Tv4Is5jupy9UXkuJ4r8\n" + 
       "Jx9DqI3Q3ur0VekYSd5tnTI4K+no9ABCFVv7+6Q45Ec2eB0xMwlqI+phcGhGMVCX\n" + 
       "1QIDAQAB\n" + 
       "-----END PUBLIC KEY-----"; 

     // decode to its constituent bytes 
     publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", ""); 
     publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); 
     BASE64Decoder base64Decoder = new BASE64Decoder(); 
     byte[] publicKeyBytes = base64Decoder.decodeBuffer(publicKeyPEM); 

     // create a key object from the bytes 
     X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); 
     KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
     PublicKey publicKey = keyFactory.generatePublic(keySpec); 

     // create a JWT consumer 
     JwtConsumer jwtConsumer = new JwtConsumerBuilder() 
      .setRequireExpirationTime() 
      .setVerificationKey(publicKey) 
      .build(); 

     // validate and decode the jwt 
     // eg: jwt = "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6Ik1DaGFtYmU0IiwiZXhwIjoxNDU2OTEwODgzLCJzY29wZSI6WyJvcGVuaWQiLCJwMnAiLCJociIsImRhcyIsIm1lIl0sImNsaWVudF9pZCI6Im1vYmlsZSIsImp0aSI6ImNZcHBMYXltVzlmNXFBZk4ifQ.QqZI9vV8IznTjN-GtUSCri9-6HH6Yl1Oae6K8-d2yjQ4fysF5d3wStdL2kMazl7xeqbtSIsw-F5Aol9eHdGAu54b9IyBEM_QIasy0lnT8xFk0Zi36NJ-7yhl_89f6SB6TGimM59xUvzXxuAw3FzWM6TbiptInrCL2TXkhS69Gng-ANPeiSITUX5A1TDInssds6ZoSb7IOUMtxPGfrbO9sBjx8aJlIu9igkqk4OX5xBmxLp3icoo98I5v9Wt_Huu7eWKBfOskMSEav4X_m5_phbAZJ_F8nWRmcxk6O7hCQdawzegnhMxP2IPIhwlWRNX_8WxkNErq2fJgdazDf8pS_Q"; 
     JwtClaims jwtDecoded = jwtConsumer.processToClaims(jwt); 
     Map<String, Object> jwtClaims = jwtDecoded.getClaimsMap(); 
     String username = (String) jwtClaims.get("username"); // "MChambe4" 

     // ensure the required scope is claimed 
     String requiredScope = "das"; 
     ArrayList scopes = (ArrayList) jwtClaims.get("scope"); 
     // ensure claims contains the required scope 
     if (!scopes.stream().anyMatch(scope -> scope == requiredScope)) { 
      throw new Exception("Required scope is not claimed: " + requiredScope); 
     } 
    } 
}