更新时间:2024-11-11 GMT+08:00
快速开始
本章节以一个被调用API为例,进行检验API中token的合法性。
操作步骤
在一个待集成的应用系统中,找到一个API接口,如/testApi。
- 在工程中增加配置信息,具体配置获取方式见准备工作中收集信息章节。
jwt.service.publickey.url: 公钥获取地址 jwt.secret.id: 密钥ID jwt.secret.appName: 集成应用名称 jwt.secret.key: 私钥 jwt.secret.publicKey: 公钥
- 定时加载公钥代码。
public void autoRefreshPublicKey() { Calendar calendar = Calendar.getInstance(); Date currentTime = calendar.getTime(); Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { try { //定时从IPDCenter获取所有公钥信息 List<String> publicKeys = HttpClientUtil.post(url, token); for (String publicKeyStr : publicKeys) { // 公钥加载到内存中 PublicKey publicKey = getPublicKey(publicKeyStr); } } catch (Exception e) { log.error("autoLoadPublicKey error", e); } } }, currentTime, refreshTime); } public PublicKey getPublicKey(String publicKeyStr) { byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory; try { keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(x509EncodedKeySpec); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { log.error("Failed to load the public key to the JWT token. Exception: {}", e.getMessage()); } return null; }
- 应用启动时加载私钥。
public PrivateKey getPrivateKey(String privateKeyStr) { try { byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyStr); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(keySpec); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { log.error("Failed to load the private key to the JWT token. Exception: {}", e.getMessage()); } return null; }
- 检验token的方法。
private static boolean verify(HttpServletRequest httpServletRequest, String publicKeyId, String token) { // 从公钥缓存中获取对应的密钥编号的公钥 PublicKey publicKey = PublicKeyCache.getInstance().publicKeysCache.get(publicKeyId); try { Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null); DecodedJWT decodedJwt = JWT.require(algorithm).ignoreIssuedAt().build().verify(token); Date expiresAt = decodedJwt.getExpiresAt(); // 验证token是否过期 if (expiresAt.before(new Date())) { LOGGER.error("The token has expired."); return false; } // 验证自己是否为接收方 List<String> audience = decodedJwt.getAudience(); if (audience != null && !audience.isEmpty() && !validAudience(httpServletRequest, audience)) { return false; } } catch (JWTVerificationException | IllegalArgumentException | SdkException e) { LOGGER.error("Verification failed. Jwt Token verification exception: {}", e.getMessage()); return false; } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Token has verify successfully."); } return true; }
- 生成token的方法。
public static String generateToken(JwtToken jwtToken, boolean isUnique) { // 私钥从缓存中通过编号获取 PrivateKey privateKey = PrivatekeyCache.getInstance().privateKeysCache.get(jwtToken.getKeyId()); Algorithm algorithm = Algorithm.RSA256(null, (RSAPrivateKey) privateKey); Date issuedAt = new Date(); // 未设置过期时间,则默认签发时间后5分钟内有效 Date expiresAt = new Date(issuedAt.getTime() + (jwtToken.getExpirationTime() <= 0 ? 300000 : jwtToken.getExpirationTime())); return "Internal:" + JWT.create() .withKeyId(jwtToken.getKeyId()) //密钥ID .withIssuer(jwtToken.getIssuer()) //用户名:用户ID .withSubject(jwtToken.getSubject()) //appName .withExpiresAt(expiresAt) .withIssuedAt(issuedAt) .withJWTId(jwtToken.getJwtId()) //随机UUID .withClaim("claims", jwtToken.getClaimMap()) //保持默认值 .sign(algorithm); }
- 在“/testApi”接口中获取token。
String token = request.getHeader("Authorization");
- 调用检验方法,检验token的合法性,并获取调用者信息。
String issuer = verify(token);
结果验证
- 调用SDK中的方法生成一个临时的token。
String token = generateToken();
- 调用API调试工具调用“/testApi”接口,调用时将步骤1中生成的token放入header中。
curl http://ip:port/xx/testApi -H "Authorization:token"
父主题: IPDCenter外部集成开发