
JWT简介公司有个合作伙伴替用户下单的需求,下单完毕需要将单据信息分享给客户看,让客户付款。由于只是一些简单的单据信息,并且没有权限校验,综合考虑安全与性能,决定使用JWT的方式实现。
JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案。具体概念自行搜索
官网介绍如下:
https://jwt.io/introduction
public enum SingletonRsaJsonWebKeyEnum {
//创建一个枚举对象,该对象天生为单例
INSTANCE;
private RsaJsonWebKey generateJwk() {
RsaJsonWebKey rsaJsonWebKey = null;
try {
rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
rsaJsonWebKey.setKeyId("www_key_customer_pay");
} catch (JoseException e) {
e.printStackTrace();
}
return rsaJsonWebKey;
}
public String getRsaJsonWebKeyJsonString() {
String keyString = "{"kty":"RSA","kid":"www_key_customer_pay","n":"lZJmKh4hM5_B0Cw2zUajuXhi6g-ZiWoNKAYIkC4upx8B9PtE541lwu6qYYoS_gP5K1tOTgJodwK95j8kfmq2Nevr8hr9FuROic0xftOJTJrkwsun22X73d5IhvG01t0NB-S_WmYF-JRcmJ6zQD1nnFgMTHn3zhEJrxByrsad-yGb0cdzFX8R4Ae383c8dL2VWyJRTOMAqW_fuR3TpSdFd-fYmjadmLIdodsWPchR88ZeEURYLjPgYAVbtBmfe8npIWHNKyPgnuy0JWdR7FQQFXvU5c-f4wccErB_o5oGHt4Nm8-S5cC3T0yp9e1CKaSiUOTCvwFfq5cX4Rf8WDzNyQ","e":"AQAB","d":"VvOTxvpbDNrb3jxF45IkTgcpYa6N8G-hlFnlkoP2hRsmlReZ2A7AUNFUZX3SSq9epBDhdcI6nq0OXpLokUFSCgjL0qRT64HwEnYiRvuMvubxBDlGrOodwL6fZSuQmLRLBgK6J0BWSktdhTAFPtwzppUdGTxyje4jtg0WznoSj1H3Gx6XN98_Nut2r5hXqP1f1nsdsE1dCaTYIJnf4kTpRBoEMjLQ2qoFr77e-wSmIrc4HFOaVzJCN4NQZjx_Vi3CdV33QX3qWEypfihEC25yGH4k7MLaP7ZSzqwv2VcvB5O7DAImYrJwQSSofiNE5yXqL6g8_0zYe91ardZngy6KzQ","p":"1UWnxrs4FdLzfi2060zfXKiEDqAh2-XLaEtlT3fUOe3Acxb0PTzRmQICwttd1pqAvqwljdapbkOHIBiGSOeQWJQEsCVxymaUVOtWxWImZmREJh8L2KoPfUIHENOmx76FmczOtTpQi4cvUnzVy45iIshC28zePTYX7l7UdxHufmM","q":"s4msVx1gdrYiCVv58db3jfXaKYWDYI8-8Fp_KdyKCFPmayYYeWl9wUEouywLqguwKKyRo7h2lKMEcgmQp0DniZVZpFpzxBu9rkmpbsS2xHL2FDt5cueNS_xgvVS3okmrW6rz6_ufBnjXKSGRMn8ZqZs6jDDdAZ-fD9iuOmCBFOM","dp":"JnmFdf2qdY1z7exy-gwJM58XC8hps1D2bB9F7JsyhyzUDi8y6qVBLrhFJUAL4r5GwZ8uuzLhqAm4o9qoxxg3WzOA0QJAUAJHejZmlf9J7CjkfngVXAX5-1_hBHEaYmiFk6R2Gg2mIDXIHLp2m11ZaOr13M9NvH84vAERlVV_z_8","dq":"C9ncnGt-AJgJKyD9IK-V67L80ZzUjT0nZGo01qiOG_qdzRjYqLsD6AvLCn_fzTu0RxsNCgeVHD6efoCPIdsw7W4EWsr1tU43eRe3rW4iulj0UWWToLgUJZ3lLNo4vOer_gMM0tjrKFw1p6tlkDW_leh_Nt3K2N6We09MQOI54w0","qi":"g66xqKV_Ci2gVgylelYk7FbypqhRsUDBrbqBZUaEK0nIW3HZGsqKB1g55vO60R4_lhftFTwrkabBtGipt6fRk3GPywj1usp3AVtR0uvBNPHGAiTYJ0hEd98uiwMQ2MteZuj3Iy-RIs9BHlN2QJVTgfZ_ulgO_viMQlfQNxrBfcA"}n"
;
// if (keyString == null) {
// keyString = SingletonRsaJsonWebKeyEnum.INSTANCE.generateJwk().toJson(RsaJsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
// }
return keyString;
}
// public static void main(String[] args) {
//
// String keyString = SingletonRsaJsonWebKeyEnum.INSTANCE.generateJwk().toJson(RsaJsonWebKey.OutputControlLevel.INCLUDE_PRIVATE);
// RsaJsonWebKey rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(SingletonRsaJsonWebKeyEnum.INSTANCE.getRsaJsonWebKeyJsonString()));
//
// }
}
@Slf4j
public class JwtUtils {
public static RsaJsonWebKey rsaJsonWebKey;
static {
try {
rsaJsonWebKey = new RsaJsonWebKey(JsonUtil.parseJson(SingletonRsaJsonWebKeyEnum.INSTANCE.getRsaJsonWebKeyJsonString()));
} catch (JoseException e) {
e.printStackTrace();
}
}
private JwtUtils() {
}
public static String createToken(Object jsonString) throws JoseException {
//
// JSON Web Token is a compact URL-safe means of representing claims/attributes to be transferred between two parties.
// This example demonstrates producing and consuming a signed JWT
//
// RsaJsonWebKey rsaJsonWebKey = SingletonRsaJsonWebKeyEnum.generateJwk();
// Give the JWK a Key ID (kid), which is just the polite thing to do
// Create the Claims, which will be the content of the JWT
JwtClaims claims = new JwtClaims();
claims.setIssuer("WWW"); // who creates the token and signs it
claims.setAudience("WWW_CUSTOMER"); // to whom the token is intended to be sent
claims.setExpirationTimeMinutesInTheFuture(48 * 60); // time when the token will expire ( minutes from now)
claims.setGeneratedJwtId(); // a unique identifier for the token
claims.setIssuedAtToNow(); // when the token was issued/created (now)
claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
claims.setSubject("测试Token"); // the subject/principal is whom the token is about
claims.setClaim("data", jsonString); // additional claims/attributes about the subject can be added
// List groups = Arrays.asList("group-one", "other-group", "group-three");
// claims.setStringListClaim("groups", groups); // multi-valued claims work too and will end up as a JSON array
// A JWT is a JWS and/or a JWE with JSON claims as the payload.
// In this example it is a JWS so we create a JsonWebSignature object.
JsonWebSignature jws = new JsonWebSignature();
// The payload of the JWS is JSON content of the JWT Claims
jws.setPayload(claims.toJson());
// The JWT is signed using the private key
jws.setKey(rsaJsonWebKey.getPrivateKey());
// Set the Key ID (kid) header because it's just the polite thing to do.
// We only have one key in this example but a using a Key ID helps
// facilitate a smooth key rollover process
jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
// Set the signature algorithm on the JWT/JWS that will integrity protect the claims
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
// Sign the JWS and produce the compact serialization or the complete JWT/JWS
// representation, which is a string consisting of three dot ('.') separated
// base64url-encoded parts in the form Header.Payload.Signature
// If you wanted to encrypt it, you can simply set this jwt as the payload
// of a JsonWebEncryption object and set the cty (Content Type) header to "jwt".
String jwt = jws.getCompactSerialization();
// Now you can do something with the JWT. Like send it to some other party
// over the clouds and through the interwebs.
return jwt;
}
public static JwtClaims validateToken(String jwt) {
// RsaJsonWebKey rsaJsonWebKey = SingletonRsaJsonWebKeyEnum.generateJwk();
// Use JwtConsumerBuilder to construct an appropriate JwtConsumer, which will
// be used to validate and process the JWT.
// The specific validation requirements for a JWT are context dependent, however,
// it typically advisable to require a (reasonable) expiration time, a trusted issuer, and
// and audience that identifies your system as the intended recipient.
// If the JWT is encrypted too, you need only provide a decryption key or
// decryption key resolver to the builder.
JwtConsumer jwtConsumer = new JwtConsumerBuilder()
.setRequireExpirationTime() // the JWT must have an expiration time
.setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
.setRequireSubject() // the JWT must have a subject claim
.setExpectedIssuer("WWW") // whom the JWT needs to have been issued by
.setExpectedAudience("WWW_CUSTOMER") // to whom the JWT is intended for
.setVerificationKey(rsaJsonWebKey.getKey()) // verify the signature with the public key
.setJwsAlgorithmConstraints( // only allow the expected signature algorithm(s) in the given context
AlgorithmConstraints.ConstraintType.PERMIT, AlgorithmIdentifiers.RSA_USING_SHA256) // which is only RS256 here
.build(); // create the JwtConsumer instance
JwtClaims jwtClaims = null;
try {
// Validate the JWT and process it to the Claims
jwtClaims = jwtConsumer.processToClaims(jwt);
log.info("JWT validation succeeded! " + jwtClaims);
} catch (InvalidJwtException e) {
// InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
// Hopefully with meaningful explanations(s) about what went wrong.
log.error("Invalid JWT! " + e);
// Programmatic access to (some) specific reasons for JWT invalidity is also possible
// should you want different error handling behavior for certain conditions.
// Whether or not the JWT has expired being one common reason for invalidity
try {
if (e.hasExpired()) {
log.error("JWT expired at " + e.getJwtContext().getJwtClaims().getExpirationTime());
}
// Or maybe the audience was invalid
if (e.hasErrorCode(ErrorCodes.AUDIENCE_INVALID)) {
log.error("JWT had wrong audience: " + e.getJwtContext().getJwtClaims().getAudience());
}
}catch (MalformedClaimException e1){
log.error("验证客户支付token异常",e1);
}
throw new MallBusinessException(StatusEnum.CUSTOMER_PAY_TOKEN_AUTHENTICATION_ERROR);
}
return jwtClaims;
}
public static void main(String[] args) throws Exception {
String json = "{"name":"小二","age":"18"}";
String jwt = createToken(json);
// String jwt = "eyJraWQiOiJ5empfa2V5X2N1c3RvbWVyX3BheSIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJZWkoiLCJhdWQiOiJZWkpfQ1VTVE9NRVIiLCJleHAiOjE2MzQxMTI2MDQsImp0aSI6Ikl5VXJYS2FkQkNSUThTODMwTVBpSFEiLCJpYXQiOjE2MzQxMTI1NDQsIm5iZiI6MTYzNDExMjQyNCwic3ViIjoi5LqR5LmL5a625Zyo57q_5ZWG5Z-O5a6i5oi35L6n5pSv5LuYVG9rZW4iLCJkYXRhIjoie1wibmFtZVwiOlwi5bCP5LqMXCIsXCJhZ2VcIjpcIjE4XCJ9In0.hfN9FxUOpr52QlYcpONswFhCYiwNWezeRAOU9iMZTNuIdJownd4Aku4trvsvSqw6FmlgwikdjDkBK8jz3mkyREeEzqlbQmlcB2Z8cz2ASy7v1mNoKvmha8l0uJ04H7c6Tottq_Ktr74ENVaaWRV-EkINHqFfg86CSiuueriEal0JKErYQGUPhWT1IO36s_sPHxAN3TzOgDBkkICxmf9ty1EgxQ3GXY_BRWdIFM4QoztLq2US0bxfNZZbBG4eE8dG3AwBDbQrjN4ESxDeXmuaqODVySRb2Nr1B-F0cT5DPJgrSH1cYqsy-BjOKdLDlBgA16ACYq8MebCCkFz3VNwGkA";
JwtClaims result = validateToken(jwt);
System.out.println("开始:" + jwt);
System.out.println("结果:" + result.getClaimValue("data"));
System.out.println("结果:" + result);
System.out.println("结果:" + result.getExpirationTime());
}
}
### 测试结果
开始:eyJraWQiOiJ5empfa2V5X2N1c3RvbWVyX3BheSIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJZWkoiLCJhdWQiOiJZWkpfQ1VTVE9NRVIiLCJleHAiOjE2MzQ3MzE0NTcsImp0aSI6ImR6UXJZeVg2c2EydjFWRmJ1S1ZQX0EiLCJpYXQiOjE2MzQ1NTg2NTgsIm5iZiI6MTYzNDU1ODUzOCwic3ViIjoi5LqR5LmL5a625Zyo57q_5ZWG5Z-O5a6i5oi35L6n5pSv5LuYVG9rZW4iLCJkYXRhIjoie1wibmFtZVwiOlwi5bCP5LqMXCIsXCJhZ2VcIjpcIjE4XCJ9In0.YIq2OgIdI2l676aFN92HH4_gKjwPSE4TZRN01ADk3XXKIseXFCmYc7Sl2VhoF762oFylnJk_PUZgVST1scSQzKhm7L2-mSEqO3-xyV7tUmV06TmLHq5qoW6dxVLxhpo2hsYT9uLryDMyln-Is1cZXCSu8zhop75AYKjpJ-7xImxIFR9SgVo7pOpcSIsiZd3lzfUbvpNRb26CyAegpphKofVRMM6ZjhRQRY7YqzxLaNQiSMNiJMsuDO7XSbXIfUSHJPFwoq_Nq66ebt2O5830pDu38DdKcTfY3w7vbHOewYTHgVCngVFF4UUD-f76kfw2n5GwGIgmYK4JAfDgj6qTnw
结果:{“name”:“小二”,“age”:“18”}
结果:JWT Claims Set:{iss=YZJ, aud=YZJ_CUSTOMER, exp=1634731457, jti=dzQrYyX6sa2v1VFbuKVP_A, iat=1634558658, nbf=1634558538, sub=云之家在线商城客户侧支付Token, data={“name”:“小二”,“age”:“18”}}
结果:NumericDate{1634731457 -> 2021-10-20 下午08时04分17秒}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)