和风天气

pom.xml

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.16</version>
        </dependency>

        <!-- 加密算法 -->
        <dependency>
            <groupId>net.i2p.crypto</groupId>
            <artifactId>eddsa</artifactId>
            <version>0.3.0</version>
        </dependency>

 

import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.Test;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Base64;
import java.util.Map;


public class WeatherEdDSA {

    static {
        // 注册 Bouncy Castle 提供者
        Security.addProvider(new BouncyCastleProvider());
    }

    public static void main(String[] args) {
        // 1.生成 公钥和私钥
        Map<String, String> keyMap = genPublicPrivateKey();
        // 2.授权获取jwt格式的token
        String jwtToken = authToken(keyMap.get("privateKey"));
        // 3.通过公钥验证 jwt token
        boolean b = validateQWeatherToken(jwtToken,  keyMap.get("publicKey"));
        System.out.println(b);
    }



    public static String authToken(String privateKeyString) {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString.trim());

        try {
            // Base64url header + payload
            String data = buildHeaderPayload();

            // Private key
            PKCS8EncodedKeySpec encoded = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("Ed25519", "BC");
            PrivateKey privateKey = keyFactory.generatePrivate(encoded);
            // Sign
            final Signature s = Signature.getInstance("EdDSA");
            s.initSign(privateKey);
            s.update(data.getBytes(StandardCharsets.UTF_8));
            byte[] signature = s.sign();

            String signatureString = Base64.getEncoder().encodeToString(signature);

            // Print Token
            String jwt = data + "." + signatureString;
            return jwt;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }



    /**
     * 验证和风天气JWT Token
     * @param jwtToken 待验证的Token字符串
     * @param base64PublicKey Base64编码的ED25519公钥(需去除PEM头尾)
     * @return 验证通过返回true,失败抛出异常
     */
    public static boolean validateQWeatherToken(String jwtToken, String base64PublicKey) {
        try{
            // 1. 解码Base64公钥
            byte[] publicKeyBytes = Base64.getDecoder().decode(base64PublicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);

            // 2. 使用ED25519算法初始化公钥
            KeyFactory keyFactory = KeyFactory.getInstance(EdDSANamedCurveTable.ED_25519, "BC");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            // 3. 创建Ed25519验证器
            JWTSigner signer = JWTSignerUtil.createSigner(EdDSANamedCurveTable.ED_25519, publicKey);
            // 4. 验证Token
            return JWT.of(jwtToken).setSigner(signer).verify();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }



    private static String buildHeaderPayload() {
        // Header
        String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"CA5CM8YUVG\"}";

        // Payload
        long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
        long exp = iat + 1*24*60*60;
        String payloadJson = "{\"sub\": \"4A89NRJ6WW\", \"iat\": " + iat + ", \"exp\": " + exp + "}";

        // Base64url header+payload
        String headerEncoded = Base64.getEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payloadEncoded = Base64.getEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
        return headerEncoded + "." + payloadEncoded;
    }

    public static Map<String, String> genPublicPrivateKey() {
        try {
            // 1. 创建 KeyPairGenerator 实例
            KeyPairGenerator keyGen = KeyPairGenerator.getInstance("Ed25519", "BC");
            // 2. 生成密钥对
            KeyPair keyPair = keyGen.generateKeyPair();
            // 3. 获取公钥和私钥的字节数组
            byte[] publicKey = keyPair.getPublic().getEncoded();
            byte[] privateKey = keyPair.getPrivate().getEncoded();
            // 4. 转换为 Base64 字符串
            String publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey);
            String privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey);

            return MapUtil.builder("publicKey", publicKeyBase64)
                    .put("privateKey", privateKeyBase64)
                    .build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Test
    public void qweatherApi() {
        String baseUrl = "https://xxxxxx.re.qweatherapi.com/";
//        String token = authToken();
        String token = "eyJhbGciOiAiRWREU0EiLCAia2lkIjogIkNBNUNNOFlVVkcifQ==.eyJzdWIiOiAiNEE4OU5SSjZXVyIsICJpYXQiOiAxNzQ3NjM1NDc5LCAiZXhwIjogMTc0NzcyMTg3OX0=.8G2GkYh1jm0_whE80Db00IyN1M6TaKKRdx8GkVbal1YRO0EeC11cFOrQGZV7dYy5DKjdCYn7B23NvZGbk3xmCg==";


        // 实时天气
        String weatherNow = baseUrl + "v7/weather/now";
        HttpResponse execute = HttpRequest.get(weatherNow + "?location=101270101").bearerAuth(token).execute();

        if(200 == execute.getStatus()) {
            String body = execute.body();
            String s = execute.contentEncoding();
            System.out.println("内容编码: "+s);
            System.out.println("实时天气: "+body);
        }
//
//        // 逐小时天气预报(24h, 72h, 168h)
//        String weatherHours = baseUrl + "v7/weather/24h";
//        execute = HttpRequest.get(weatherHours + "?location=101270101").bearerAuth(token).execute();
//        if(200 == execute.getStatus()) {
//            String body = execute.body();
//            System.out.println("逐小时天气预报: "+body);
//        }
//
//        // 天气灾害预警
//        String warningNow = baseUrl + "/v7/warning/now";
//        execute = HttpRequest.get(warningNow+"?location=101270101").bearerAuth(token).execute();
//        if(200 == execute.getStatus()) {
//            String body = execute.body();
//            System.out.println("天气灾害预警: "+body);
//        }

//        Map<String, String> header = new HashMap<>();
//        header.put("Authorization", "Bearer "+token);
//        String s = HttpUtils.sendGZipGet(weatherNow, "location=101270101", header);
//        System.out.println(s);

    }


}

 

posted @ 2025-05-20 17:56  真某人  阅读(43)  评论(0)    收藏  举报