web-dev-qa-db-ja.com

JavaのJWT(JSON Web Token)ライブラリ

私はJavaとAngularJSを使用して開発されたWebアプリケーションに取り組んでおり、トークンの認証と承認を実装することを選択しました。演習の目的で、資格情報をサーバーに送信し、ランダムなトークンを生成して保管し、クライアントに送り返すところまで来ました。サーバーへのすべてのリクエストで、ヘッダーにトークンを添付し、完全に機能します。認証の観点からは完璧であり、それ以上は必要ありません。

ただし、ユーザーの種類(admin、通常のユーザー...)、およびそのid、またはその他の一意のフィールドを追跡する必要があります。理解したように、ログインアクション中にクライアントに送り返すトークンでそれを暗号化する必要があります。あれは正しいですか?

あなたが使用し、そのようなトークンを生成、暗号化、復号化できるJWTライブラリはありますか?ライブラリのAPIとMaven依存関係へのリンクをいただければ幸いです。

ありがとう

66

答えが必要な人がいたら、

このライブラリを使用しました: http://connect2id.com/products/nimbus-jose-jwt Maven here: http://mvnrepository.com/artifact/com.nimbusds/nimbus- jose-jwt/2.10.1

22

JJWTは、JVMおよびAndroid用のJWTライブラリを最も使いやすく理解することを目指しています。

https://github.com/jwtk/jjwt

49
Les Hazlewood

このライブラリはうまく機能しているようです: 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

13
Marquez

https://jwt.io/ を参照すると、jwtを含む多くの言語でJava実装を見つけることができます。また、このサイトでは、これらの実装(サポートしているアルゴリズムと....)の比較を提供しています。

Javaには、これらのライブラリが記載されています。

12
Alireza Fattahi

IETFは、wikiでjoseライブラリを提案しています: http://trac.tools.ietf.org/wg/jose/trac/wiki

署名に使用することを強くお勧めします。私はJava男ではありませんが、jose4jは良い選択肢のようです。ニースの例もあります: https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

更新:jwt.ioは、いくつかのjwt関連ライブラリとそれらの機能のきちんとした比較を提供します。確認する必要があります!

他のJava開発者が好むものについて聞きたいです。

7
Priyeshj

これは小さくて完全であることがわかりました https://github.com/auth0/Java-jwt

5
mfirry

このページは、Javaを含むさまざまな言語の実装への参照を保持し、機能を比較します。 http://kjur.github.io/jsjws/index_mat.html

3
Hans Z.

署名されていない暗号化されていないトークンのみを解析する必要がある場合は、次のコードを使用できます。

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;
}
2
Anton Duzenko

https://github.com/networknt/jsontoken

これは元のGoogle 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の両方の著者です。

2
Steve Hu