mirror of
https://github.com/chillzhuang/SpringBlade.git
synced 2024-11-23 19:09:25 +08:00
🎉 3.7.0.RELEASE Token加密传输
This commit is contained in:
parent
abc412290c
commit
85daa7e425
@ -21,9 +21,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springblade.core.launch.props.BladeProperties;
|
||||||
import org.springblade.gateway.props.AuthProperties;
|
import org.springblade.gateway.props.AuthProperties;
|
||||||
import org.springblade.gateway.provider.AuthProvider;
|
import org.springblade.gateway.provider.AuthProvider;
|
||||||
import org.springblade.gateway.provider.ResponseProvider;
|
import org.springblade.gateway.provider.ResponseProvider;
|
||||||
|
import org.springblade.gateway.utils.JwtCrypto;
|
||||||
import org.springblade.gateway.utils.JwtUtil;
|
import org.springblade.gateway.utils.JwtUtil;
|
||||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
@ -39,6 +41,8 @@ import reactor.core.publisher.Mono;
|
|||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import static org.springblade.gateway.utils.JwtCrypto.BLADE_CRYPTO_AES_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 鉴权认证
|
* 鉴权认证
|
||||||
*
|
*
|
||||||
@ -50,6 +54,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
public class AuthFilter implements GlobalFilter, Ordered {
|
public class AuthFilter implements GlobalFilter, Ordered {
|
||||||
private final AuthProperties authProperties;
|
private final AuthProperties authProperties;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
private final BladeProperties bladeProperties;
|
||||||
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
|
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -66,6 +71,10 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||||||
}
|
}
|
||||||
String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
|
String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
|
||||||
String token = JwtUtil.getToken(auth);
|
String token = JwtUtil.getToken(auth);
|
||||||
|
//校验 加密Token 合法性
|
||||||
|
if (JwtUtil.isCrypto(auth)) {
|
||||||
|
token = JwtCrypto.decryptToString(token, bladeProperties.getEnvironment().getProperty(BLADE_CRYPTO_AES_KEY));
|
||||||
|
}
|
||||||
Claims claims = JwtUtil.parseJWT(token);
|
Claims claims = JwtUtil.parseJWT(token);
|
||||||
if (claims == null) {
|
if (claims == null) {
|
||||||
return unAuth(resp, "请求未授权");
|
return unAuth(resp, "请求未授权");
|
||||||
|
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the dreamlu.net developer nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
* Author: Chill 庄骞 (smallchill@163.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.gateway.utils;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.Base64Utils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import reactor.util.annotation.Nullable;
|
||||||
|
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JwtCrypto
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
public class JwtCrypto {
|
||||||
|
|
||||||
|
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
public static final String BLADE_CRYPTO_AES_KEY = "blade.token.aes-key";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64加密
|
||||||
|
*
|
||||||
|
* @param content 文本内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
public static String encryptToString(String content, String aesTextKey) {
|
||||||
|
return Base64Utils.encodeToString(encrypt(content, aesTextKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64加密
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
public static String encryptToString(byte[] content, String aesTextKey) {
|
||||||
|
return Base64Utils.encodeToString(encrypt(content, aesTextKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param content 文本内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(String content, String aesTextKey) {
|
||||||
|
return encrypt(content.getBytes(DEFAULT_CHARSET), aesTextKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param content 文本内容
|
||||||
|
* @param charset 编码
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(String content, Charset charset, String aesTextKey) {
|
||||||
|
return encrypt(content.getBytes(charset), aesTextKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(byte[] content, String aesTextKey) {
|
||||||
|
return encrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64解密
|
||||||
|
*
|
||||||
|
* @param content 文本内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static String decryptToString(@Nullable String content, @Nullable String aesTextKey) {
|
||||||
|
if (!StringUtils.hasText(content) || !StringUtils.hasText(aesTextKey)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] hexBytes = decrypt(Base64Utils.decode(content.getBytes(DEFAULT_CHARSET)), aesTextKey);
|
||||||
|
return new String(hexBytes, DEFAULT_CHARSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @param aesTextKey 文本密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] decrypt(byte[] content, String aesTextKey) {
|
||||||
|
return decrypt(content, Objects.requireNonNull(aesTextKey).getBytes(DEFAULT_CHARSET));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密
|
||||||
|
*
|
||||||
|
* @param content 内容
|
||||||
|
* @param aesKey 密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] encrypt(byte[] content, byte[] aesKey) {
|
||||||
|
return aes(Pkcs7Encoder.encode(content), aesKey, Cipher.ENCRYPT_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密
|
||||||
|
*
|
||||||
|
* @param encrypted 内容
|
||||||
|
* @param aesKey 密钥
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
public static byte[] decrypt(byte[] encrypted, byte[] aesKey) {
|
||||||
|
return Pkcs7Encoder.decode(aes(encrypted, aesKey, Cipher.DECRYPT_MODE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ase加密
|
||||||
|
*
|
||||||
|
* @param encrypted 内容
|
||||||
|
* @param aesKey 密钥
|
||||||
|
* @param mode 模式
|
||||||
|
* @return byte[]
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
private static byte[] aes(byte[] encrypted, byte[] aesKey, int mode) {
|
||||||
|
Assert.isTrue(aesKey.length == 32, "IllegalAesKey, aesKey's length must be 32");
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||||
|
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
|
||||||
|
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
|
||||||
|
cipher.init(mode, keySpec, iv);
|
||||||
|
return cipher.doFinal(encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供基于PKCS7算法的加解密接口.
|
||||||
|
*/
|
||||||
|
private static class Pkcs7Encoder {
|
||||||
|
private static final int BLOCK_SIZE = 32;
|
||||||
|
|
||||||
|
private static byte[] encode(byte[] src) {
|
||||||
|
int count = src.length;
|
||||||
|
// 计算需要填充的位数
|
||||||
|
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
|
||||||
|
// 获得补位所用的字符
|
||||||
|
byte pad = (byte) (amountToPad & 0xFF);
|
||||||
|
byte[] pads = new byte[amountToPad];
|
||||||
|
for (int index = 0; index < amountToPad; index++) {
|
||||||
|
pads[index] = pad;
|
||||||
|
}
|
||||||
|
int length = count + amountToPad;
|
||||||
|
byte[] dest = new byte[length];
|
||||||
|
System.arraycopy(src, 0, dest, 0, count);
|
||||||
|
System.arraycopy(pads, 0, dest, count, amountToPad);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] decode(byte[] decrypted) {
|
||||||
|
int pad = decrypted[decrypted.length - 1];
|
||||||
|
if (pad < 1 || pad > BLOCK_SIZE) {
|
||||||
|
pad = 0;
|
||||||
|
}
|
||||||
|
if (pad > 0) {
|
||||||
|
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
|
||||||
|
}
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,6 +17,7 @@ package org.springblade.gateway.utils;
|
|||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
|
import lombok.Getter;
|
||||||
import org.springblade.core.launch.constant.TokenConstant;
|
import org.springblade.core.launch.constant.TokenConstant;
|
||||||
import org.springblade.gateway.props.JwtProperties;
|
import org.springblade.gateway.props.JwtProperties;
|
||||||
|
|
||||||
@ -31,17 +32,15 @@ import java.util.Base64;
|
|||||||
public class JwtUtil {
|
public class JwtUtil {
|
||||||
|
|
||||||
public static String BEARER = TokenConstant.BEARER;
|
public static String BEARER = TokenConstant.BEARER;
|
||||||
|
public static String CRYPTO = TokenConstant.CRYPTO;
|
||||||
public static Integer AUTH_LENGTH = 7;
|
public static Integer AUTH_LENGTH = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* jwt配置
|
* jwt配置
|
||||||
*/
|
*/
|
||||||
|
@Getter
|
||||||
private static JwtProperties jwtProperties;
|
private static JwtProperties jwtProperties;
|
||||||
|
|
||||||
public static JwtProperties getJwtProperties() {
|
|
||||||
return jwtProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setJwtProperties(JwtProperties properties) {
|
public static void setJwtProperties(JwtProperties properties) {
|
||||||
if (JwtUtil.jwtProperties == null) {
|
if (JwtUtil.jwtProperties == null) {
|
||||||
JwtUtil.jwtProperties = properties;
|
JwtUtil.jwtProperties = properties;
|
||||||
@ -55,6 +54,20 @@ public class JwtUtil {
|
|||||||
return Base64.getEncoder().encodeToString(getJwtProperties().getSignKey().getBytes(StandardCharsets.UTF_8));
|
return Base64.getEncoder().encodeToString(getJwtProperties().getSignKey().getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断token类型为crypto
|
||||||
|
*
|
||||||
|
* @param auth token
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public static Boolean isCrypto(String auth) {
|
||||||
|
if ((auth != null) && (auth.length() > AUTH_LENGTH)) {
|
||||||
|
String headStr = auth.substring(0, 6).toLowerCase();
|
||||||
|
return headStr.compareTo(CRYPTO) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取token串
|
* 获取token串
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user