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

org.dromara.hutool.json.jwt.JWT Maven / Gradle / Ivy

There is a newer version: 6.0.0.M3
Show newest version
/*
 * Copyright (c) 2013-2024 Hutool Team and hutool.cn
 *
 * 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 org.dromara.hutool.json.jwt;

import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.exception.ValidateException;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.jwt.signers.AlgorithmUtil;
import org.dromara.hutool.json.jwt.signers.JWTSigner;
import org.dromara.hutool.json.jwt.signers.JWTSignerUtil;
import org.dromara.hutool.json.jwt.signers.NoneJWTSigner;

import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyPair;
import java.util.List;
import java.util.Map;

/**
 * JSON Web Token (JWT),基于JSON的开放标准((RFC 7519)用于在网络应用环境间传递声明。
*

* 结构:header.payload.signature *

    *
  • header:主要声明了JWT的签名算法
  • *
  • payload:主要承载了各种声明并传递明文数据
  • *
  • signature:拥有该部分的JWT被称为JWS,也就是签了名的JWS
  • *
* *

* 详细介绍见;https://www.jianshu.com/p/576dbf44b2ae *

* * @author looly * @since 5.7.0 */ public class JWT implements RegisteredPayload { private final JWTHeader header; private final JWTPayload payload; private Charset charset; private JWTSigner signer; private List tokens; /** * 创建空的JWT对象 * * @return JWT */ public static JWT of() { return new JWT(); } /** * 创建并解析JWT对象 * * @param token JWT Token字符串,格式为xxxx.yyyy.zzzz * @return JWT */ public static JWT of(final String token) { return new JWT(token); } /** * 构造 */ public JWT() { this.header = new JWTHeader(); this.payload = new JWTPayload(); this.charset = CharsetUtil.UTF_8; } /** * 构造 * * @param token JWT Token字符串,格式为xxxx.yyyy.zzzz */ public JWT(final String token) { this(); parse(token); } /** * 解析JWT内容 * * @param token JWT Token字符串,格式为xxxx.yyyy.zzzz,不能为空 * @return this * @throws IllegalArgumentException 给定字符串为空 */ public JWT parse(final String token) throws IllegalArgumentException { Assert.notBlank(token, "Token String must be not blank!"); final List tokens = splitToken(token); this.tokens = tokens; this.header.parse(tokens.get(0), this.charset); this.payload.parse(tokens.get(1), this.charset); return this; } /** * 设置编码 * * @param charset 编码 * @return this */ public JWT setCharset(final Charset charset) { this.charset = charset; return this; } /** * 设置密钥,默认算法是:HS256(HmacSHA256) * * @param key 密钥 * @return this */ public JWT setKey(final byte[] key) { // 检查头信息中是否有算法信息 final String algorithmId = (String) this.header.getClaim(JWTHeader.ALGORITHM); if (StrUtil.isNotBlank(algorithmId)) { return setSigner(algorithmId, key); } return setSigner(JWTSignerUtil.hs256(key)); } /** * 设置签名算法 * * @param algorithmId 签名算法ID,如HS256 * @param key 密钥 * @return this */ public JWT setSigner(final String algorithmId, final byte[] key) { return setSigner(JWTSignerUtil.createSigner(algorithmId, key)); } /** * 设置签名算法 * * @param algorithmId 签名算法ID,如HS256 * @param key 密钥 * @return this * @since 5.7.2 */ public JWT setSigner(final String algorithmId, final Key key) { return setSigner(JWTSignerUtil.createSigner(algorithmId, key)); } /** * 设置非对称签名算法 * * @param algorithmId 签名算法ID,如HS256 * @param keyPair 密钥对 * @return this * @since 5.7.2 */ public JWT setSigner(final String algorithmId, final KeyPair keyPair) { return setSigner(JWTSignerUtil.createSigner(algorithmId, keyPair)); } /** * 设置签名算法 * * @param signer 签名算法 * @return this */ public JWT setSigner(final JWTSigner signer) { this.signer = signer; return this; } /** * 获取JWT算法签名器 * * @return JWT算法签名器 */ public JWTSigner getSigner() { return this.signer; } /** * 获取所有头信息 * * @return 头信息 */ public JSONObject getHeaders() { return this.header.getClaimsJson(); } /** * 获取头 * * @return 头信息 * @since 5.7.2 */ public JWTHeader getHeader() { return this.header; } /** * 获取头信息 * * @param name 头信息名称 * @return 头信息 */ public Object getHeader(final String name) { return this.header.getClaim(name); } /** * 获取算法ID(alg)头信息 * * @return 算法头信息 * @see JWTHeader#ALGORITHM */ public String getAlgorithm() { return (String) this.header.getClaim(JWTHeader.ALGORITHM); } /** * 设置JWT头信息 * * @param name 头名 * @param value 头 * @return this */ public JWT setHeader(final String name, final Object value) { this.header.setClaim(name, value); return this; } /** * 增加JWT头信息 * * @param headers 头信息 * @return this */ public JWT addHeaders(final Map headers) { this.header.addHeaders(headers); return this; } /** * 获取所有载荷信息 * * @return 载荷信息 */ public JSONObject getPayloads() { return this.payload.getClaimsJson(); } /** * 获取载荷对象 * * @return 载荷信息 * @since 5.7.2 */ public JWTPayload getPayload() { return this.payload; } /** * 获取载荷信息 * * @param name 载荷信息名称 * @return 载荷信息 */ public Object getPayload(final String name) { return getPayload().getClaim(name); } /** * 获取payload并获取类型 * * @param Bean类型 * @param propertyName 需要提取的属性名称 * @param propertyType 需要提取的属性类型 * @return 载荷信息 * @throws ValidateException 传入的类型不匹配payload类型 * @since 6.0.0 */ public T getPayload(final String propertyName, final Class propertyType) { return getPayload().getClaimsJson().get(propertyName, propertyType); } /** * 设置JWT载荷信息 * * @param name 载荷名 * @param value 头 * @return this */ @Override public JWT setPayload(final String name, final Object value) { this.payload.setClaim(name, value); return this; } /** * 增加JWT载荷信息 * * @param payloads 载荷信息 * @return this */ public JWT addPayloads(final Map payloads) { this.payload.addPayloads(payloads); return this; } /** * 签名生成JWT字符串 * * @return JWT字符串 */ public String sign() { return sign(this.signer); } /** * 签名生成JWT字符串,计算方式为(以HS256为例): *
	 * HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
	 * 
* *

此方法会补充如下的header:

*
    *
  • 当用户未定义"typ"时,不设置默认值
  • *
  • 当用户未定义"alg"时,根据传入的{@link JWTSigner}对象类型,赋值对应ID
  • *
* * @param signer 自定义JWT签名器,非空 * @return JWT字符串 */ public String sign(final JWTSigner signer) { Assert.notNull(signer, () -> new JWTException("No Signer provided!")); // 检查头信息中是否有算法信息 final String algorithm = (String) this.header.getClaim(JWTHeader.ALGORITHM); if (StrUtil.isBlank(algorithm)) { this.header.setAlgorithm(AlgorithmUtil.getId(signer.getAlgorithm())); } final String headerBase64 = Base64.encodeUrlSafe(this.header.toString(), charset); final String payloadBase64 = Base64.encodeUrlSafe(this.payload.toString(), charset); final String sign = signer.sign(headerBase64, payloadBase64); return StrUtil.format("{}.{}.{}", headerBase64, payloadBase64, sign); } /** * 验证JWT Token是否有效 * * @return 是否有效 */ public boolean verify() { return verify(this.signer); } /** * 验证JWT是否有效,验证包括: * *
    *
  • Token是否正确
  • *
  • {@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间
  • *
  • {@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间
  • *
  • {@link JWTPayload#ISSUED_AT}: 签发时间不能晚于当前时间
  • *
* * @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。 * @return 是否有效 * @see JWTValidator * @since 5.7.4 */ public boolean validate(final long leeway) { if (!verify()) { return false; } // 校验时间字段 try { JWTValidator.of(this).validateDate(DateUtil.now(), leeway); } catch (final ValidateException e) { return false; } return true; } /** * 使用指定签名器,验证JWT Token是否有效
* 如果签名器为{@code null},或者{@link NoneJWTSigner},表示这个JWT无签名,签名部分必须为空 * * @param signer 签名器(签名算法),如果为{@code null},默认为{@link NoneJWTSigner} * @return 是否有效 */ public boolean verify(JWTSigner signer) { if (null == signer) { // 如果无签名器提供,默认认为是无签名JWT信息 signer = NoneJWTSigner.NONE; } final List tokens = this.tokens; if (CollUtil.isEmpty(tokens)) { throw new JWTException("No token to verify!"); } return signer.verify(tokens.get(0), tokens.get(1), tokens.get(2)); } /** * 将JWT字符串拆分为3部分,无加密算法则最后一部分是"" * * @param token JWT Token * @return 三部分内容 */ private static List splitToken(final String token) { final List tokens = SplitUtil.split(token, StrUtil.DOT); if (3 != tokens.size()) { throw new JWTException("The token was expected 3 parts, but got {}.", tokens.size()); } return tokens; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy