用于 Java 的 JWT (JSON Web 令牌)库

我正在开发一个使用 Java 和 AngularJS 开发的 Web 应用程序,并选择实现令牌认证和授权。 出于练习的目的,我已经到了将凭据发送到服务器、生成一个随机令牌存储它并将其发送回客户机的地步。 对服务器的每个请求,我都会在头部附加令牌,它工作得很完美。 因为身份验证的观点是完美的,不需要更多。

然而,我现在想要跟踪用户类型(admin,普通用户...) ,以及它的 id,或任何其他唯一的字段; 正如我所理解的,我必须在登录操作期间发送回客户端的令牌中加密它。是这样吗?

您是否使用了任何 JWT 库,并且可以生成、加密和解密这些令牌? 如果能提供到库的 API 和 Maven 依赖关系的链接,我将不胜感激。

谢谢

145565 次浏览

This library seems to work well: https://code.google.com/p/jsontoken/ .

It depends on Google Guava. Here are the Maven artifacts:

<dependency>
<groupId>com.googlecode.jsontoken</groupId>
<artifactId>jsontoken</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>

The library is in fact used by Google Wallet.

Here is how to create a jwt, and to verify it and deserialize it:

import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.util.Calendar;
import java.util.List;


import net.oauth.jsontoken.JsonToken;
import net.oauth.jsontoken.JsonTokenParser;
import net.oauth.jsontoken.crypto.HmacSHA256Signer;
import net.oauth.jsontoken.crypto.HmacSHA256Verifier;
import net.oauth.jsontoken.crypto.SignatureAlgorithm;
import net.oauth.jsontoken.crypto.Verifier;
import net.oauth.jsontoken.discovery.VerifierProvider;
import net.oauth.jsontoken.discovery.VerifierProviders;


import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;


import com.google.common.collect.Lists;
import com.google.gson.JsonObject;




/**
* Provides static methods for creating and verifying access tokens and such.
* @author davidm
*
*/
public class AuthHelper {


private static final String AUDIENCE = "NotReallyImportant";


private static final String ISSUER = "YourCompanyOrAppNameHere";


private static final String SIGNING_KEY = "LongAndHardToGuessValueWithSpecialCharacters@^($%*$%";


/**
* Creates a json web token which is a digitally signed token that contains a payload (e.g. userId to identify
* the user). The signing key is secret. That ensures that the token is authentic and has not been modified.
* Using a jwt eliminates the need to store authentication session information in a database.
* @param userId
* @param durationDays
* @return
*/
public static String createJsonWebToken(String userId, Long durationDays)    {
//Current time and signing algorithm
Calendar cal = Calendar.getInstance();
HmacSHA256Signer signer;
try {
signer = new HmacSHA256Signer(ISSUER, null, SIGNING_KEY.getBytes());
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
}


//Configure JSON token
JsonToken token = new net.oauth.jsontoken.JsonToken(signer);
token.setAudience(AUDIENCE);
token.setIssuedAt(new org.joda.time.Instant(cal.getTimeInMillis()));
token.setExpiration(new org.joda.time.Instant(cal.getTimeInMillis() + 1000L * 60L * 60L * 24L * durationDays));


//Configure request object, which provides information of the item
JsonObject request = new JsonObject();
request.addProperty("userId", userId);


JsonObject payload = token.getPayloadAsJsonObject();
payload.add("info", request);


try {
return token.serializeAndSign();
} catch (SignatureException e) {
throw new RuntimeException(e);
}
}


/**
* Verifies a json web token's validity and extracts the user id and other information from it.
* @param token
* @return
* @throws SignatureException
* @throws InvalidKeyException
*/
public static TokenInfo verifyToken(String token)
{
try {
final Verifier hmacVerifier = new HmacSHA256Verifier(SIGNING_KEY.getBytes());


VerifierProvider hmacLocator = new VerifierProvider() {


@Override
public List<Verifier> findVerifier(String id, String key){
return Lists.newArrayList(hmacVerifier);
}
};
VerifierProviders locators = new VerifierProviders();
locators.setVerifierProvider(SignatureAlgorithm.HS256, hmacLocator);
net.oauth.jsontoken.Checker checker = new net.oauth.jsontoken.Checker(){


@Override
public void check(JsonObject payload) throws SignatureException {
// don't throw - allow anything
}


};
//Ignore Audience does not mean that the Signature is ignored
JsonTokenParser parser = new JsonTokenParser(locators,
checker);
JsonToken jt;
try {
jt = parser.verifyAndDeserialize(token);
} catch (SignatureException e) {
throw new RuntimeException(e);
}
JsonObject payload = jt.getPayloadAsJsonObject();
TokenInfo t = new TokenInfo();
String issuer = payload.getAsJsonPrimitive("iss").getAsString();
String userIdString =  payload.getAsJsonObject("info").getAsJsonPrimitive("userId").getAsString();
if (issuer.equals(ISSUER) && !StringUtils.isBlank(userIdString))
{
t.setUserId(new ObjectId(userIdString));
t.setIssued(new DateTime(payload.getAsJsonPrimitive("iat").getAsLong()));
t.setExpires(new DateTime(payload.getAsJsonPrimitive("exp").getAsLong()));
return t;
}
else
{
return null;
}
} catch (InvalidKeyException e1) {
throw new RuntimeException(e1);
}
}




}


public class TokenInfo {
private ObjectId userId;
private DateTime issued;
private DateTime expires;
public ObjectId getUserId() {
return userId;
}
public void setUserId(ObjectId userId) {
this.userId = userId;
}
public DateTime getIssued() {
return issued;
}
public void setIssued(DateTime issued) {
this.issued = issued;
}
public DateTime getExpires() {
return expires;
}
public void setExpires(DateTime expires) {
this.expires = expires;
}
}

This is based on code here: https://developers.google.com/wallet/instant-buy/about-jwts And Here: https://code.google.com/p/wallet-online-sample-java/source/browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa

IETF has suggested jose libs on it's wiki: http://trac.tools.ietf.org/wg/jose/trac/wiki

I would highly recommend using them for signing. I am not a Java guy, but seems like jose4j seems like a good option. Has nice examples as well: https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

Update: jwt.io provides a neat comparison of several jwt related libraries, and their features. A must check!

I would love to hear about what other java devs prefer.

JJWT aims to be the easiest to use and understand JWT library for the JVM and Android:

https://github.com/jwtk/jjwt

I found this to be small and complete https://github.com/auth0/java-jwt

https://github.com/networknt/jsontoken

This is a fork of original google jsontoken

It has not been updated since Sep 11, 2012 and depends on some old packages.

What I have done:

Convert from Joda time to Java 8 time. So it requires Java 8.
Covert Json parser from Gson to Jackson as I don't want to include two Json parsers to my projects.
Remove google collections from dependency list as it is stopped long time ago.
Fix thread safe issue with Java Mac.doFinal call.

All existing unit tests passed along with some newly added test cases.

Here is a sample to generate token and verify the token. For more information, please check https://github.com/networknt/light source code for usage.

I am the author of both jsontoken and Omni-Channel Application Framework.

This page keeps references to implementations in various languages, including Java, and compares features: http://kjur.github.io/jsjws/index_mat.html

If you only need to parse unsigned unencrypted tokens you could use this code:

boolean parseJWT_2() {
String authToken = getToken();
String[] segments = authToken.split("\\.");
String base64String = segments[1];
int requiredLength = (int)(4 * Math.ceil(base64String.length() / 4.0));
int nbrPaddings = requiredLength - base64String.length();


if (nbrPaddings > 0) {
base64String = base64String + "====".substring(0, nbrPaddings);
}


base64String = base64String.replace("-", "+");
base64String = base64String.replace("_", "/");


try {
byte[] data = Base64.decode(base64String, Base64.DEFAULT);


String text;
text = new String(data, "UTF-8");
tokenInfo = new Gson().fromJson(text, TokenInfo.class);
} catch (Exception e) {
e.printStackTrace();
return false;
}


return true;
}

By referring to https://jwt.io/ you can find jwt implementations in many languages including java. Also the site provide some comparison between these implementation (the algorithms they support and ....).

For java these are mentioned libraries: