JWT Token 使用 RS256 和 ES256 签名

使用 RS256 签名

创建 RSA 密钥

安装 openssl 服务,执行如下指令生成密钥对。

# 创建私钥
openssl genrsa -out rsa_private.pem 2048
# 创建公钥
openssl rsa -in rsa_private.pem -outform PEM -pubout -out rsa_public.pem

创建和验证 JWT Token

将创建好的密钥对放到 resources/crt 目录下,读取私钥进行签名,读取公钥进行验签。可自定义 token 中携带的信息,确保自定义信息中没有敏感信息,例如密码、手机号等。

package com.uniedu.sa.questionnaire;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

public class JwtUtils {

    private static final long EXPIRE = 10 * 60 * 60;
    private static final String DEVICE_ID = "device_id";
    private static final String PUBLIC_KEY_PATH = "/home/user/rsa_public.pem";
    private static final String PRIVATE_KEY_PATH = "/home/user/rsa_private.pem";

    public static void main(String[] args) {
        // 代码生成密钥方式
        // KeyPair keyPair = generateKeyPair(2048);
        // PublicKey publicKey = keyPair.getPublic();
        // PrivateKey privateKey = keyPair.getPrivate();
        // 读取密钥文件方式-注意修改密钥文件目录
        PublicKey publicKey = getRSAPublicKey();
        PrivateKey privateKey = getRSAPrivateKey();
        String token = createAccessJwtToken(privateKey, "YJ1001");
        System.err.println(token);
        boolean validatorToken = validatorToken(publicKey, token);
        System.err.println(validatorToken);
        String id = parseAccessJwtToken(publicKey, token);
        System.err.println(id);
    }

    /**
     * 生成token字符串的方法
     *
     * @param deviceId
     * @return
     */
    public static String createAccessJwtToken(PrivateKey privateKey, String deviceId) {
        Claims claims = Jwts.claims().setSubject(deviceId);
        claims.put(DEVICE_ID, deviceId);

        String accessToken = Jwts.builder()
                .setClaims(claims)
                .setIssuer("User")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();

        return accessToken;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param accessToken
     * @return
     */
    public static boolean validatorToken(PublicKey publicKey, String accessToken) {
        try {
            if (StringUtils.isEmpty(accessToken)) {
                return false;
            }
            Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取deviceId
     *
     * @param accessToken
     * @return
     */
    public static String parseAccessJwtToken(PublicKey publicKey, String accessToken) {
        try {
            if (StringUtils.isEmpty(accessToken)) {
                return null;
            }
            Jws<Claims> jws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
            Claims claims = jws.getBody();
            return claims.get(DEVICE_ID, String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成 RSA 密钥
     *
     * @param keysize
     * @return
     */
    public static KeyPair generateKeyPair(int keysize) {
        try {
            // 获取指定算法的密钥对生成器
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器(指定密钥长度, 使用默认的安全随机数源)
            generator.initialize(keysize);
            // 随机生成一对密钥(包含公钥和私钥)
            return generator.generateKeyPair();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取PrivateKey对象
     *
     * @return
     */
    private static PrivateKey getRSAPrivateKey() {
        try {
            InputStream inputStream = new FileInputStream(PRIVATE_KEY_PATH);
            String privateKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
            String privateKeyPEM = privateKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
                    .replaceAll("\\-*END.*KEY\\-*", "")
                    .replaceAll("\r", "")
                    .replaceAll("\n", "");
            Security.addProvider(new BouncyCastleProvider());
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKeyPEM));
            KeyFactory factory = KeyFactory.getInstance("RSA");
            return factory.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取PublicKey对象
     *
     * @return
     */
    private static PublicKey getRSAPublicKey() {
        try {
            InputStream inputStream = new FileInputStream(PUBLIC_KEY_PATH);
            String publicKeyBase64 = IOUtils.toString(inputStream, "UTF-8");
            String publicKeyPEM = publicKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
                    .replaceAll("\\-*END.*KEY\\-*", "")
                    .replaceAll("\r", "")
                    .replaceAll("\n", "");
            Security.addProvider(new BouncyCastleProvider());
            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKeyPEM));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
            return publicKey;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

使用 ES256 加密

创建 ES256 密钥

安装 openssl 服务,执行如下指令生成密钥对,这里注意需要将私钥转换为 pkcs8 格式。

# 创建私钥
openssl ecparam -genkey -name prime256v1 -noout -out ec_private.pem
# 创建公钥
openssl ec -in ec_private.pem -pubout -out ec_public.pem
# 转换私钥
openssl pkcs8 -topk8 -inform PEM -outform DER -in ec_private.pem -nocrypt > ec_private_pkcs8

创建和验证 JWT Token

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.util.StringUtils;

import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Date;

public class JwtUtils {

    public static final String DEVICE_ID = "device_id";
    public static final long EXPIRE = 10 * 60 * 60;

    public static void main(String[] args) {
        String token = createAccessJwtToken("YJ1001");
        System.err.println(token);
        boolean validatorToken = validatorToken(token);
        System.err.println(validatorToken);
        String id = parseAccessJwtToken(token);
        System.err.println(id);
    }

    /**
     * 生成token字符串的方法
     *
     * @param deviceId
     * @return
     */
    public static String createAccessJwtToken(String deviceId) {
        PrivateKey privateKey = getECPrivateKey();

        Claims claims = Jwts.claims().setSubject(deviceId);
        claims.put(DEVICE_ID, deviceId);

        String accessToken = Jwts.builder()
                .setClaims(claims)
                .setIssuer("User")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .signWith(SignatureAlgorithm.ES256, privateKey)
                .compact();

        return accessToken;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param accessToken
     * @return
     */
    public static boolean validatorToken(String accessToken) {
        try {
            if (StringUtils.isEmpty(accessToken)) {
                return false;
            }
            PublicKey publicKey = getECPublicKey();
            Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取deviceId
     *
     * @param accessToken
     * @return
     */
    public static String parseAccessJwtToken(String accessToken) {
        try {
            if (StringUtils.isEmpty(accessToken)) {
                return null;
            }
            PublicKey publicKey = getECPublicKey();
            Jws<Claims> jws = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(accessToken);
            Claims claims = jws.getBody();
            return claims.get(DEVICE_ID, String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取PrivateKey对象
     *
     * @return
     */
    private static PrivateKey getECPrivateKey() {
        try {
            Security.addProvider(new BouncyCastleProvider());
            KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "BC");
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/ec_private_pkcs8");
            byte[] devicePriKeybytes = IOUtils.toByteArray(inputStream);
            PKCS8EncodedKeySpec devicePriKeySpec = new PKCS8EncodedKeySpec(devicePriKeybytes);
            return keyFactory.generatePrivate(devicePriKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取PublicKey对象
     *
     * @return
     */
    private static PublicKey getECPublicKey() {
        try {
            Security.addProvider(new BouncyCastleProvider());
            KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "BC");

            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("crt/ec_public.pem");
            String publicKeyBase64 = IOUtils.toString(inputStream, "UTF-8");

            publicKeyBase64 = publicKeyBase64.replaceAll("\\-*BEGIN.*KEY\\-*", "")
                    .replaceAll("\\-*END.*KEY\\-*", "")
                    .replaceAll("\r", "")
                    .replaceAll("\n", "");
            byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64);

            X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(publicKeyBytes);
            return keyFactory.generatePublic(pubX509);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
以下是使用 PHP 实现 JWTRS256 算法的示例代码: ```php <?php // 生成 JWT Token function generateToken($payload, $privateKey) { $header = array('alg' => 'RS256', 'typ' => 'JWT'); $jwt = base64_encode(json_encode($header)) . '.' . base64_encode(json_encode($payload)); openssl_sign($jwt, $signature, $privateKey, 'SHA256'); $jwt .= '.' . base64_encode($signature); return $jwt; } // 验证 JWT Token function verifyToken($jwt, $publicKey) { list($headerEncoded, $payloadEncoded, $signatureEncoded) = explode('.', $jwt); $header = json_decode(base64_decode($headerEncoded), true); $payload = json_decode(base64_decode($payloadEncoded), true); $signature = base64_decode($signatureEncoded); $jwt = $headerEncoded . '.' . $payloadEncoded; $isVerified = openssl_verify($jwt, $signature, $publicKey, 'SHA256'); return $isVerified ? $payload : null; } // 加载密钥 $privateKey = openssl_pkey_get_private(file_get_contents('private.key')); $publicKey = openssl_pkey_get_public(file_get_contents('public.key')); // 生成 Token $payload = array('sub' => '1234567890', 'name' => 'John Doe', 'iat' => 1516239022); $jwt = generateToken($payload, $privateKey); echo $jwt . "\n"; // 验证 Token $verifiedPayload = verifyToken($jwt, $publicKey); var_dump($verifiedPayload); ?> ``` 在以上代码中,`generateToken` 函数用于生成 JWT Token,其中 `$payload` 参数是包含用户信息的数组,`$privateKey` 是使用 `openssl_pkey_get_private` 加载的私钥。`verifyToken` 函数用于验证 JWT Token,其中 `$jwt` 参数是要验证的 Token 字符串,`$publicKey` 是使用 `openssl_pkey_get_public` 加载的公钥。在示例代码中,私钥和公钥保存在文件 `private.key` 和 `public.key` 中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值