jwt教程 - 用于Java的JWT(JSON Web Token)库




jwt框架 jwt实现 (9)

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

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

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

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

谢谢


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

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

更新:jwt.io提供了几个jwt相关库及其功能的简洁比较。 一定要检查!

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





该库似乎运行良好: https://code.google.com/p/jsontoken/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 = "[email protected]^($%*$%";

    /**
     * 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-jwtshttps://code.google.com/p/wallet-online-sample-java/source/browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa此处: https://developers.google.com/wallet/instant-buy/about-jwtshttps://code.google.com/p/wallet-online-sample-java/source/browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa


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的作者。


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

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

获取在任何servlet容器中运行的任何Web应用程序(Tomcat,Jetty,Glassfish,等等......)。连续重新部署应用程序10次或者20次(可能只需触摸服务器的autodeploy目录中的WAR即可。

除非有人实际测试过这个,否则很有可能在经过几次重新部署后你会得到一个OutOfMemoryError,因为应用程序没有注意自己清理。您甚至可以通过此测试在服务器中找到错误。

问题是,容器的生命周期比应用程序的生命周期长。您必须确保容器可能对应用程序的对象或类的所有引用都可以进行垃圾回收。

如果只有一个引用在您的Web应用程序取消部署后仍然存在,则相应的类加载器将导致您的Web应用程序的所有类都无法进行垃圾回收。

您的应用程序启动的线程,ThreadLocal变量,日志记录附加程序是导致类加载器泄漏的一些常见嫌疑。





java json web token jwt