引入maven依赖
<!--jwt用户登录数据加密-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- 将RSA加密后的文件bytes 和 string 的相互转化 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>2.9.9</version>
</dependency>
核心类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
@Slf4j
public class RsaUtils {
/**
* 获取公钥对象
*
* @param publicKeyStr 公钥字符串常量
* @return 公钥对象
* @throws Exception
*/
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
byte[] bytes = Base64.decodeBase64(publicKeyStr);
return getPublicKey(bytes);
}
/**
* 获取私钥数据对象
*
* @param privateKeyStr 私钥字符串常量
* @return 私钥对象
* @throws Exception
*/
public static PrivateKey getPrivateKey(String privateKeyStr) throws Exception {
byte[] bytes = Base64.decodeBase64(privateKeyStr);
return getPrivateKey(bytes);
}
/**
* 获取公钥
*
* @param bytes 公钥的字节形式
* @return
* @throws Exception
*/
public static PublicKey getPublicKey(byte[] bytes) throws Exception {
X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
/**
* 获取密钥
*
* @param bytes 私钥的字节形式
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(byte[] bytes) throws Exception {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePrivate(spec);
}
/**
* 根据密文,生成rsa公钥和私钥,并写入指定文件
* @param publicKeyFilename 公钥文件路径
* @param secret 生成密钥的密文
* @throws Exception
*/
public static void generateKey(String publicKeyFilename, String secret) throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(2048, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 获取公钥并写出
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
// keyMap.put(publicKeyFilename,publicKeyBytes);
}
/**
* 根据密文,生成rsa公钥和私钥,并写入指定文件
*
* @param secret 生成密钥的密文
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static void generateKey(String secret) {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom secureRandom = new SecureRandom(secret.getBytes());
keyPairGenerator.initialize(2048, secureRandom);
KeyPair keyPair = keyPairGenerator.genKeyPair();
// 获取公钥并写出
byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
String publicKeyStr = Base64.encodeBase64String(publicKeyBytes);
log.info("publicKeyStr: " + publicKeyStr);
log.info("===========================================================");
// 获取私钥并写出
byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
String privateKeyStr = Base64.encodeBase64String(privateKeyBytes);
log.info("privateKeyStr: " + privateKeyStr);
} catch (Exception e) {
log.error( "初始化公钥私钥异常: " + e.getMessage(),e);
}
}
public static void main(String[] args) {
// String secret = "zhou@LoginInfo(Auth}*^3256)&kong_local%";
// String secret = "zhou@LoginInfo(Auth}*^3256)&kong_test%";
String secret = "zhou@LoginInfo(Auth}*^6874)&kong_prod%";
generateKey(secret);
}
}
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* @author zhoushisheng
* 用户登录认证拦截
*/
@Slf4j
public class UserAuthenticationHandler implements HandlerInterceptor {
private static ThreadLocal<UserInfo> tokenThread = new ThreadLocal<>();
private static ThreadLocal<Boolean> interceptThread = new ThreadLocal<Boolean>();
private JwtProperties jwtProperties;
public UserAuthenticationHandler() {
}
public UserAuthenticationHandler(JwtProperties jwtProperties) {
this.jwtProperties = jwtProperties;
}
/**
* 对用户token 有效性验证
* 在解析JWT字符串时,如果密钥不正确,将会解析失败,
* 抛出SignatureException异常,说明该JWT字符串是伪造的
* 在解析JWT字符串时,如果‘过期时间字段’已经早于当前时间,
* 将会抛出ExpiredJwtException异常,说明本次请求已经失效
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
try {
// 请求跨域验证放行 "OPTIONS"
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
interceptThread.set(true);
String token = request.getParameter(TOKEN);
log.info("token: " + token);
if (StringUtils.isEmpty(token)) {
throw new OpenApiServiceException(OPEN_API_USER_LOGIN_TOKEN_ERROR);
}
UserInfo userInfo = JwtUtils.getInfoFromToken(token,
jwtProperties.getPublicKey());
if (userInfo != null) {
tokenThread.set(userInfo);
return true;
} else {
throw new OpenApiServiceException(OPEN_API_USER_LOGIN_TOKEN_ERROR);
}
} catch (Exception e) {
throw new OpenApiServiceException(OPEN_API_USER_LOGIN_TOKEN_ERROR);
}
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
/**
* token用户资源的释放
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) throws Exception {
tokenThread.remove();
interceptThread.remove();
}
public static UserInfo getUserInfo() {
return tokenThread.get();
}
public static Boolean getInterceptBool() {
return interceptThread.get() == null ?
false : interceptThread.get();
}
}
/**
* mvc入口处理类
* @author zhoushisheng
*/
@Slf4j
@Configuration
@EnableConfigurationProperties(JwtProperties.class)
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private JwtProperties jwtProperties;
private static List<String> paths = new ArrayList<>();
static {
paths.add("/swagger-ui.html/**");
paths.add("/swagger-ui/**");
paths.add("/swagger-resources/**");
paths.add("/v2/api-docs/**");
paths.add("/v3/api-docs/**");
paths.add("/webjars/**");
paths.add("/doc.html/**");
paths.add("/favicon.ico");
paths.add("/sync/**");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserAuthenticationHandler(jwtProperties))
.addPathPatterns("/**")
.excludePathPatterns(paths);
}
/**
* 处理跨域问题
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE","PATCH")
.allowedHeaders("*")
.maxAge(3600)
.allowCredentials(true);
}
}
/**
* @author zhoushisheng
* jwt的配置文件
*/
@Slf4j
@Data
@ConfigurationProperties(prefix = "aaa.xxx.ccc")
public class JwtProperties {
/**
* 加密的秘钥数据源
*/
private String secret;
/**
* token过期时间单位为分钟
*/
private int expire;
/**
* 公钥初始对象
*/
private PublicKey publicKey;
/**
* 公钥字符常量值
*/
private String publicKeyStr;
/**
* 私钥初始对象
*/
private PrivateKey privateKey;
/**
* 私钥字符常量值
*/
private String privateKeyStr;
/**
* 服务加载初始化秘钥对
*/
@PostConstruct
public void initData() {
try {
privateKey = RsaUtils.getPrivateKey(privateKeyStr);
publicKey = RsaUtils.getPublicKey(publicKeyStr);
log.info("=============RsaUtils...initData=============");
} catch (Exception e) {
log.error("RsaUtils initData error: " + e.getMessage(),e);
}
}
}