All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.hiwepy.jwt.token.SignedWithSecretKeyJWTRepository Maven / Gradle / Ivy

/*
 * Copyright (c) 2018, hiwepy (https://github.com/hiwepy).
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.github.hiwepy.jwt.token;

import java.security.Key;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.hiwepy.jwt.JwtPayload;
import com.github.hiwepy.jwt.exception.ExpiredJwtException;
import com.github.hiwepy.jwt.exception.IncorrectJwtException;
import com.github.hiwepy.jwt.exception.InvalidJwtToken;
import com.github.hiwepy.jwt.exception.JwtException;
import com.github.hiwepy.jwt.exception.NotObtainedJwtException;
import com.github.hiwepy.jwt.utils.JJwtUtils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Clock;
import io.jsonwebtoken.CompressionCodec;
import io.jsonwebtoken.CompressionCodecResolver;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.InvalidClaimException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.JwtClock;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.JwtParserBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.MissingClaimException;
import io.jsonwebtoken.PrematureJwtException;
import io.jsonwebtoken.RequiredTypeException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.InvalidKeyException;
import io.jsonwebtoken.security.SignatureException;

/**
 *  JSON Web Token (JWT) with signature 
 * https://github.com/jwtk/jjwt
 */
public class SignedWithSecretKeyJWTRepository implements JwtRepository {

	private Logger logger = LoggerFactory.getLogger(getClass());
	private long allowedClockSkewSeconds = -1;
	private CompressionCodec compressWith = CompressionCodecs.DEFLATE;
    private CompressionCodecResolver compressionCodecResolver;
    private Clock clock = new JwtClock();
    private static final Map PARSER_CONTEXT = new ConcurrentHashMap<>();
 
	public JwtParser getJwtParser(Key secretKey, boolean checkExpiry) {
		
		String key = String.format("%s-%s", secretKey.hashCode() , checkExpiry);
		JwtParser ret = PARSER_CONTEXT.get(key);
		if (ret != null) {
			return ret;
		}
		
		JwtParserBuilder jwtParserBuilder = checkExpiry ? Jwts.parserBuilder() : JJwtUtils.parserBuilder();
		// 时钟
		jwtParserBuilder.setClock(clock)
		// 签名Key
		.setSigningKey(secretKey)
		// 允许的时间误差
		.setAllowedClockSkewSeconds(getAllowedClockSkewSeconds());
		// 压缩方式解析器
		if(null != getCompressionCodecResolver() ) {
			jwtParserBuilder.setCompressionCodecResolver(getCompressionCodecResolver());
		}
		ret = jwtParserBuilder.build();
		PARSER_CONTEXT.put( key, ret);
		return ret;
	}
    
    /**
	 * Issue JSON Web Token (JWT)
	 * @author :hiwepy
	 * @param secretKey		: Signing key
	 * @param jwtId			: Jwt Id
	 * @param subject		: Jwt Subject
	 * @param issuer 		: Jwt Issuer
	 * @param audience 		: Jwt Audience
	 * @param roles			: The Roles
	 * @param permissions	: The Perms
	 * @param algorithm		: Supported algorithms:
	 *  

none: No digital signature or MAC performed

*

HS256: HMAC using SHA-256

*

HS384: HMAC using SHA-384

*

HS512: HMAC using SHA-512

*

ES256: ECDSA using P-256 and SHA-256

*

ES384: ECDSA using P-384 and SHA-384

*

ES512: ECDSA using P-521 and SHA-512

*

RS256: RSASSA-PKCS-v1_5 using SHA-256

*

RS384: RSASSA-PKCS-v1_5 using SHA-384

*

RS512: RSASSA-PKCS-v1_5 using SHA-512

*

PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256

*

PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384

*

PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512

* @param period : Jwt Expiration Cycle * @return JSON Web Token (JWT) * @throws JwtException When Authentication Exception */ @Override public String issueJwt(Key secretKey, String jwtId, String subject, String issuer, String audience, String roles, String permissions, String algorithm, long period) throws JwtException { Map claims = new HashMap(); claims.put("roles", roles); claims.put("perms", permissions); return this.issueJwt(secretKey, jwtId, subject, issuer, audience, claims, algorithm, period); } /** * Issue JSON Web Token (JWT) * @author :hiwepy * @param secretKey : Signing key * @param jwtId : Jwt Id * @param subject : Jwt Subject * @param issuer : Jwt Issuer * @param audience : Jwt Audience * @param claims : Jwt Claims * @param algorithm : Supported algorithms: *

none: No digital signature or MAC performed

*

HS256: HMAC using SHA-256

*

HS384: HMAC using SHA-384

*

HS512: HMAC using SHA-512

*

ES256: ECDSA using P-256 and SHA-256

*

ES384: ECDSA using P-384 and SHA-384

*

ES512: ECDSA using P-521 and SHA-512

*

RS256: RSASSA-PKCS-v1_5 using SHA-256

*

RS384: RSASSA-PKCS-v1_5 using SHA-384

*

RS512: RSASSA-PKCS-v1_5 using SHA-512

*

PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256

*

PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384

*

PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512

* @param period : Jwt Expiration Cycle * @return JSON Web Token (JWT) * @throws JwtException When Authentication Exception */ @Override public String issueJwt(Key secretKey, String jwtId, String subject, String issuer, String audience, Map claims, String algorithm, long period) throws JwtException { try { JwtBuilder builder = JJwtUtils .jwtBuilder(jwtId, subject, issuer, audience, claims, period) // 压缩类型 .compressWith(getCompressWith()) // 设置算法(必须) .signWith(secretKey, SignatureAlgorithm.forName(algorithm)); // 签发时间 Date now = this.getClock().now(); builder.setIssuedAt(now); // 有效期起始时间 //builder.setNotBefore(now); // Token过期时间 if (period >= 0) { // 有效时间 Date expiration = new Date(now.getTime() + period); builder.setExpiration(expiration); } return builder.compact(); } catch (InvalidKeyException e) { throw new JwtException(e); } catch (SignatureException e) { throw new JwtException(e); } } /** * Verify the validity of JWT * @author : hiwepy * @param secretKey : *

If the jws was signed with a SecretKey, the same SecretKey should be specified on the JwtParser.

*

If the jws was signed with a PrivateKey, that key's corresponding PublicKey (not the PrivateKey) should be specified on the JwtParser.

* @param token : JSON Web Token (JWT) * @param checkExpiry : If Check validity. * @return If Validity * @throws JwtException When Authentication Exception */ @Override public boolean verify(Key secretKey, String token, boolean checkExpiry) throws JwtException { try { // Retrieve / verify the JWT claims according to the app requirements JwtParser jwtParser = this.getJwtParser(secretKey, checkExpiry); // 解密JWT,如果无效则会抛出异常 Jws jws = jwtParser.parseClaimsJws(token); Claims claims = jws.getBody(); Date issuedAt = claims.getIssuedAt(); Date notBefore = claims.getNotBefore(); Date expiration = claims.getExpiration(); Date now = this.getClock().now(); if (logger.isDebugEnabled()) { logger.debug("JWT IssuedAt:" + issuedAt); logger.debug("JWT NotBefore:" + notBefore); logger.debug("JWT Expiration:" + expiration); logger.debug("JWT Now:" + now); } if(notBefore != null && now.getTime() <= notBefore.getTime()) { throw new NotObtainedJwtException(String.format("JWT was not obtained before this timestamp : [%s].", notBefore)); } if(expiration != null && expiration.getTime() < now.getTime()) { throw new ExpiredJwtException("Expired JWT value. "); } return true; } catch (MalformedJwtException e) { throw new IncorrectJwtException(e); } catch (MissingClaimException e) { throw new IncorrectJwtException(e); } catch (io.jsonwebtoken.ExpiredJwtException e) { throw new ExpiredJwtException(e); } catch (InvalidClaimException e) { throw new InvalidJwtToken(e); } catch (PrematureJwtException e) { throw new InvalidJwtToken(e); } catch (RequiredTypeException e) { throw new InvalidJwtToken(e); } catch (JwtException e) { throw new IncorrectJwtException(e); } catch (IllegalArgumentException e) { throw new IncorrectJwtException(e); } } /** * Parser JSON Web Token (JWT) * @author :hiwepy * @param secretKey : *

If the jws was signed with a SecretKey, the same SecretKey should be specified on the JwtParser.

*

If the jws was signed with a PrivateKey, that key's corresponding PublicKey (not the PrivateKey) should be specified on the JwtParser.

* @param token : JSON Web Token (JWT) * @param checkExpiry : If Check validity. * @return JwtPlayload {@link JwtPayload} * @throws JwtException When Authentication Exception */ @Override public JwtPayload getPlayload(Key secretKey, String token, boolean checkExpiry) throws JwtException { try { // Retrieve / verify the JWT claims according to the app requirements JwtParser jwtParser = this.getJwtParser(secretKey, checkExpiry); Jws jws = jwtParser.parseClaimsJws(token); return JJwtUtils.payload(jws.getBody()); } catch (MalformedJwtException e) { throw new IncorrectJwtException(e); } catch (MissingClaimException e) { throw new IncorrectJwtException(e); } catch (io.jsonwebtoken.ExpiredJwtException e) { throw new ExpiredJwtException(e); } catch (InvalidClaimException e) { throw new InvalidJwtToken(e); } catch (PrematureJwtException e) { throw new InvalidJwtToken(e); } catch (RequiredTypeException e) { throw new InvalidJwtToken(e); } catch (JwtException e) { throw new IncorrectJwtException(e); } catch (IllegalArgumentException e) { throw new IncorrectJwtException(e); } catch (ParseException e) { throw new IncorrectJwtException(e); } } public long getAllowedClockSkewSeconds() { return allowedClockSkewSeconds; } public void setAllowedClockSkewSeconds(long allowedClockSkewSeconds) { this.allowedClockSkewSeconds = allowedClockSkewSeconds; } public CompressionCodec getCompressWith() { return compressWith; } public void setCompressWith(CompressionCodec compressWith) { this.compressWith = compressWith; } public CompressionCodecResolver getCompressionCodecResolver() { return compressionCodecResolver; } public void setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) { this.compressionCodecResolver = compressionCodecResolver; } public Clock getClock() { return clock; } public void setClock(Clock clock) { this.clock = clock; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy