diff --git a/CHANGELOG.md b/CHANGELOG.md index ed25528cd..a53d86014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.7.3 (2021-06-28) +# 5.7.3 (2021-06-29) ### 🐣新特性 * 【core 】 增加Convert.toSet方法(issue#I3XFG2@Gitee) @@ -15,6 +15,7 @@ * 【jwt 】 JWT修改默认有序,并规定payload日期格式为秒数 * 【json 】 增加JSONWriter * 【core 】 IdUtil增加getWorkerId和getDataCenterId(issueI3Y5NI@Gitee) +* 【core 】 JWTValidator增加leeway重载 ### 🐞Bug修复 * 【json 】 修复XML转义字符的问题(issue#I3XH09@Gitee) diff --git a/hutool-jwt/src/main/java/cn/hutool/jwt/Claims.java b/hutool-jwt/src/main/java/cn/hutool/jwt/Claims.java index 0731a97ba..6279fec9e 100644 --- a/hutool-jwt/src/main/java/cn/hutool/jwt/Claims.java +++ b/hutool-jwt/src/main/java/cn/hutool/jwt/Claims.java @@ -20,6 +20,7 @@ import java.util.Map; public class Claims implements Serializable { private static final long serialVersionUID = 1L; + // 时间使用秒级时间戳表示 private final JSONConfig CONFIG = JSONConfig.create().setDateFormat("#sss").setOrder(true); private JSONObject claimJSON; diff --git a/hutool-jwt/src/main/java/cn/hutool/jwt/JWTValidator.java b/hutool-jwt/src/main/java/cn/hutool/jwt/JWTValidator.java index 9830c496f..7561ecc9a 100644 --- a/hutool-jwt/src/main/java/cn/hutool/jwt/JWTValidator.java +++ b/hutool-jwt/src/main/java/cn/hutool/jwt/JWTValidator.java @@ -97,9 +97,9 @@ public class JWTValidator { * 检查JWT的以下三两个时间: * * *

* 如果某个时间没有设置,则不检查(表示无限制) @@ -109,7 +109,28 @@ public class JWTValidator { * @throws ValidateException 验证失败的异常 */ public JWTValidator validateDate(Date dateToCheck) throws ValidateException { - validateDate(this.jwt.getPayload(), dateToCheck); + validateDate(this.jwt.getPayload(), dateToCheck, 0L); + return this; + } + + /** + * 检查JWT的以下三两个时间: + * + *

+ *

+ * 如果某个时间没有设置,则不检查(表示无限制) + * + * @param dateToCheck 被检查的时间,一般为当前时间 + * @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。 + * @return this + * @throws ValidateException 验证失败的异常 + */ + public JWTValidator validateDate(Date dateToCheck, long leeway) throws ValidateException { + validateDate(this.jwt.getPayload(), dateToCheck, leeway); return this; } @@ -154,42 +175,77 @@ public class JWTValidator { * 检查JWT的以下三两个时间: * *

*

* 如果某个时间没有设置,则不检查(表示无限制) * - * @param payload {@link JWTPayload} - * @param dateToCheck 被检查的时间,一般为当前时间 + * @param payload {@link JWTPayload} + * @param now 当前时间 + * @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。 * @throws ValidateException 验证异常 */ - private static void validateDate(JWTPayload payload, Date dateToCheck) throws ValidateException { - if (null == dateToCheck) { + private static void validateDate(JWTPayload payload, Date now, long leeway) throws ValidateException { + if (null == now) { // 默认当前时间 - dateToCheck = DateUtil.date(); + now = DateUtil.date(); + // truncate millis + now.setTime(now.getTime() / 1000 * 1000); } - // 检查生效时间(被检查时间必须晚于生效时间) + // 检查生效时间(生效时间不能晚于当前时间) final Date notBefore = payload.getClaimsJson().getDate(JWTPayload.NOT_BEFORE); - if (null != notBefore && dateToCheck.before(notBefore)) { - throw new ValidateException("Current date [{}] is before 'nbf' [{}]", - dateToCheck, DateUtil.date(notBefore)); - } + validateNotAfter(JWTPayload.NOT_BEFORE, notBefore, now, leeway); - // 检查失效时间(被检查时间必须早于失效时间) + // 检查失效时间(失效时间不能早于当前时间) final Date expiresAt = payload.getClaimsJson().getDate(JWTPayload.EXPIRES_AT); - if (null != expiresAt && dateToCheck.after(expiresAt)) { - throw new ValidateException("Current date [{}] is after 'exp' [{}]", - dateToCheck, DateUtil.date(expiresAt)); - } + validateNotBefore(JWTPayload.EXPIRES_AT, expiresAt, now, leeway); - // 检查签发时间(被检查时间必须晚于签发时间) + // 检查签发时间(签发时间不能晚于当前时间) final Date issueAt = payload.getClaimsJson().getDate(JWTPayload.ISSUED_AT); - if (null != issueAt && dateToCheck.before(issueAt)) { - throw new ValidateException("Current date [{}] is before 'iat' [{}]", - dateToCheck, DateUtil.date(issueAt)); + validateNotAfter(JWTPayload.ISSUED_AT, issueAt, now, leeway); + } + + /** + * 验证指定字段的时间不能晚于当前时间 + * + * @param fieldName 字段名 + * @param dateToCheck 被检查的字段日期 + * @param now 当前时间 + * @param leeway 容忍空间,单位:秒。向后容忍 + * @throws ValidateException 验证异常 + */ + private static void validateNotAfter(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException { + if (null == dateToCheck) { + return; + } + now.setTime(now.getTime() + leeway * 1000); + if (dateToCheck.after(now)) { + throw new ValidateException("'{}':[{}] is after now:[{}]", + fieldName, DateUtil.date(dateToCheck), DateUtil.date(now)); + } + } + + /** + * 验证指定字段的时间不能早于当前时间 + * + * @param fieldName 字段名 + * @param dateToCheck 被检查的字段日期 + * @param now 当前时间 + * @param leeway 容忍空间,单位:秒。。向前容忍 + * @throws ValidateException 验证异常 + */ + @SuppressWarnings("SameParameterValue") + private static void validateNotBefore(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException { + if (null == dateToCheck) { + return; + } + now.setTime(now.getTime() - leeway * 1000); + if (dateToCheck.before(now)) { + throw new ValidateException("'{}':[{}] is before now:[{}]", + fieldName, DateUtil.date(dateToCheck), DateUtil.date(now)); } } }