用于Java的JWT(JSON Web Token)库

时间:2014-05-22 13:34:53

标签: java json web token jwt

我正在开发使用Java和AngularJS开发的Web应用程序,并选择实现令牌身份验证和授权。 出于练习目的,我已经到了将证书发送到服务器,生成随机令牌存储它并将其发送回客户端的程度。 在每次向服务器发出请求时,我都会在标头中附加令牌并且它可以正常工作。 因为认证的观点是完美的,不需要更多。

但是,我现在想要跟踪用户类型(管理员,普通用户......),以及它的ID或任何其他唯一字段;据我所知,我必须在令牌中加密,我在登录操作期间将其发送回客户端。这是对的吗?

您使用过JWT库吗?可以生成,加密和解密此类令牌吗? 非常感谢图书馆API和Maven依赖关系的链接。

由于

9 个答案:

答案 0 :(得分:48)

JJWT旨在最简单地使用和理解JVM和Android的JWT库:

https://github.com/jwtk/jjwt

答案 1 :(得分:21)

答案 2 :(得分:13)

这个图书馆似乎运作良好:https://code.google.com/p/jsontoken/

这取决于Google Guava。以下是Maven文物:

<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>

该库实际上是由Google电子钱包使用的。

以下是如何创建一个jwt,并对其进行验证并对其进行反序列化:

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;
    }
}

这是基于以下代码:https://developers.google.com/wallet/instant-buy/about-jwts 在这里:https://code.google.com/p/wallet-online-sample-java/source/browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa

答案 3 :(得分:12)

通过引用https://jwt.io/,您可以找到许多语言的jwt实施,包括java。该站点还提供了这些实现(它们支持的算法和....)之间的一些比较。

对于java,这些是提到的库:

答案 4 :(得分:7)

IETF在它的维基上建议了jose libs: http://trac.tools.ietf.org/wg/jose/trac/wiki

我强烈建议您使用它们进行签名。我不是一个Java人,但似乎jose4j似乎是个不错的选择。也有很好的例子:https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

  

更新:jwt.io提供了几个jwt相关的简洁比较   图书馆及其功能。必须检查!

我很想知道其他java开发者喜欢什么。

答案 5 :(得分:5)

我发现这是一个小而完整的https://github.com/auth0/java-jwt

答案 6 :(得分:3)

此页面保留对各种语言(包括Java)的实现的引用,并比较功能:http://kjur.github.io/jsjws/index_mat.html

答案 7 :(得分:2)

https://github.com/networknt/jsontoken

这是原始谷歌jsontoken的分支

自2012年9月11日起,它尚未更新,取决于一些旧包装。

我做了什么:

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.

所有现有的单元测试都与一些新添加的测试用例一起传递。

以下是生成令牌并验证令牌的示例。有关详细信息,请查看https://github.com/networknt/light源代码以了解用途。

我是jsontoken和Omni-Channel Application Framework的作者。

答案 8 :(得分:2)

如果您只需要解析未签名的未加密令牌,则可以使用以下代码:

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;
}