Библиотека JWT (JSON Web Token) для Java

Я работаю над веб-приложением, разработанным с использованием Java и AngularJS, и решил реализовать аутентификацию и авторизацию токенов. Для целей упражнения я дошел до того, что отправляю учетные данные на сервер, генерирую случайный токен и отправляю его обратно клиенту. При каждом запросе на сервер я прикрепляю токен в заголовке, и он отлично работает. Для аутентификации точка зрения идеальна и не нуждается в большем.

однако, я сейчас хотите отслеживать тип пользователя (admin, regular user...), а также это id или любое другое уникальное поле; как я понял, я должен зашифровать это в токене, который я отправляю обратно клиенту во время входа в систему. Это верно?

есть ли библиотека JWT, которую вы использовали и можете генерировать, шифровать и расшифровывать такие токены? Ссылка на API библиотеки и зависимость Maven была бы очень признательна.

спасибо

9 ответов


JJWT стремится быть самым простым в использовании и понимании библиотеки JWT для JVM и Android:

https://github.com/jwtk/jjwt


Если кто-то в ответ,

Я использовал эту библиотеку: http://connect2id.com/products/nimbus-jose-jwt Maven здесь:http://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt/2.10.1


эта библиотека, кажется, работает хорошо: 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 Wallet.

вот как создать 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


ссылаясь на https://jwt.io/ Вы можете найти jwt реализации на многих языках, включая java. Также сайт предоставляет некоторое сравнение между этими реализациями (алгоритмы, которые они поддерживают и)....).

на java это упомянутые библиотеки:


IETF предложил jose libs на его wiki: http://trac.tools.ietf.org/wg/jose/trac/wiki

Я настоятельно рекомендую использовать их для подписания. Я не Java-парень, но, похоже, jose4j кажется хорошим вариантом. Имеет хорошие примеры:https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

обновление: jwt.io обеспечивает аккуратное сравнение нескольких связанных jwt библиотеки и их особенности. Обязательно чек!

Я хотел бы услышать о том, что предпочитают другие разработчики java.


Я обнаружил, что это маленький и полный https://github.com/auth0/java-jwt


эта страница содержит ссылки на реализации на разных языках, включая Java, и сравнивает функции:http://kjur.github.io/jsjws/index_mat.html


https://github.com/networknt/jsontoken

это вилка оригинального google jsontoken

он не обновлялся с сентября 11, 2012 и зависит от некоторых старых пакетов.

что я сделал:

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 и многоканальных приложений.


Если вам нужно только разобрать неподписанные незашифрованные токены, вы можете использовать этот код:

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