首页 文章

用于Java的JWT(JSON Web Token)库

提问于
浏览
61

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

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

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

谢谢

9 回答

  • 0

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

    https://github.com/jwtk/jjwt

  • 10
  • 20

    这个库似乎运作良好: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

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

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

  • 47

    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开发者喜欢什么 .

  • 2

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

  • 7

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

  • 5

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

  • 13

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

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

相关问题