Token的对称与非对称加密

本文深入讲解了JWT(JSON Web Token)生成Token的原理与实践,包括对称加密和非对称加密两种方式,以及如何在Java环境下使用nimbus-jose-jwt库实现JWT的生成与验证。

JWT生成Token

Token在日常服务中使用频率非常高,生成Token的方式也非常多,目前使用最广泛的方法是使用JWT生成Token。使用JWT可以选择不同的加密方式保障Token的安全,并且可以自定义Token携带的信息以便于后台验证,生成的Token还能保存在前端,不需要消耗后端服务器资源。

JWT加密方式

  1. 对称加密 ,对称加密即加密解密都使用同一个密钥,HS256加密方式就是用户定义一个密钥(sercret),加密时将密钥与Token中存储用户信息的map生成token。
  2. 非对称加密 ,非对称使用公共/私钥对: 标识提供方采用私钥生成签名, JWT 的使用方获取公钥以验证签名。由于公钥 (与私钥相比) 不需要保护, 因此大多数标识提供方使其易于使用方获取和使用 (通常通过一个元数据URL)。

两种加密方法实现

-引入依赖

   <dependency>
     <groupId>com.nimbusds</groupId>
      <artifactId>nimbus-jose-jwt</artifactId>
      <version>6.0</version>
  </dependency>

对称加密

public class TokenUtils {

/**
 * 密匙
 */

private static final byte[] secret = "geibosssoftsfdjsikolkjikolkijswm".getBytes();


//生成一个token
public static String creatTokenHS256(Map<String,Object> payloadMap) throws JOSEException {

    /**
     * JWSHeader参数:加密算法法则
     *
     * JWSAlgorithm:类里面有所有的加密算法法则,直接调用。
     */
    JWSHeader jwsHeader = new JWSHeader(JWSAlgorithm.HS256);

    //建立一个载荷Payload
    Payload payload = new Payload(new JSONObject(payloadMap));

    //将头部和载荷结合在一起
    JWSObject jwsObject = new JWSObject(jwsHeader, payload);

    //建立一个密匙

    JWSSigner jwsSigner = new MACSigner(secret);

    //签名
    jwsObject.sign(jwsSigner);

    //生成token
    return jwsObject.serialize();

}

public static Map<String,Object> validHS256(String token) throws ParseException, JOSEException {
// 解析token
    JWSObject jwsObject = JWSObject.parse(token);
    //建立一个解锁密匙
    JWSVerifier jwsVerifier = new MACVerifier(secret);
    return verify(jwsObject, jwsVerifier);
}


//验证token信息
private static Map<String,Object> verify(JWSObject jwsObject,JWSVerifier jwsVerifier) throws JOSEException {
    Map<String, Object> resultMap = new HashMap<>();
    //获取到载荷
    Payload payload=jwsObject.getPayload();
    //判断token
    if (jwsObject.verify(jwsVerifier)) {
        resultMap.put("Result", 0);
        //载荷的数据解析成json对象。
        JSONObject jsonObject = payload.toJSONObject();
        resultMap.put("data", jsonObject);
        //判断token是否过期
        if (jsonObject.containsKey("exp")) {
            Long expTime = Long.valueOf(jsonObject.get("exp").toString());
            Long nowTime = DateUtils.getTime();
            //判断是否过期
            if (nowTime > expTime) {
                //已经过期
                resultMap.clear();
                resultMap.put("Result", 2);
            }
        }
    }else {
        resultMap.put("Result", 1);
    }
    return resultMap;
}

}

非对称加密

public class JwtUtils {

/**
 * 创建加密key
 */
public static RSAKey getKey() throws JOSEException {
    RSAKeyGenerator rsaKeyGenerator = new RSAKeyGenerator(2048);
    RSAKey rsaJwk = rsaKeyGenerator.generate();
    System.out.println("加密key是" + rsaJwk);
    return rsaJwk;
}

/**
 * @param payloadMap token的主题部分
 * @param rsaJwk     rsa加密密钥
 * @return 加密后的token
 * @throws JOSEException
 */
public static String creatToken(Map<String, Object> payloadMap, RSAKey rsaJwk) throws JOSEException {
    //私密钥匙
    JWSSigner signer = new RSASSASigner(rsaJwk);
    //构建token主体
    JWSObject jwsObject = new JWSObject(
            new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJwk.getKeyID()).build(),
            new Payload(new JSONObject(payloadMap))
    );
    //进行加密
    jwsObject.sign(signer);
    //生成token
    String token = jwsObject.serialize();
    return token;
}

/**
 * @param token  相关token
 * @param rsaJwk 相关密钥
 * @return
 * @throws ParseException
 * @throws JOSEException
 */
public static Map<String, Object> validToken(String token, RSAKey rsaJwk) throws ParseException, JOSEException {
    //获取到公钥
    RSAKey rsaKey = rsaJwk.toPublicJWK();
    JWSObject jwsObject = JWSObject.parse(token);
    JWSVerifier jwsVerifier = new RSASSAVerifier(rsaKey);
    //验证数据
    Map<String, Object> tokenMap = new HashMap<>();
    //记录token主体信息
    Payload payload = jwsObject.getPayload();
    //判断token是否合法
    if (jwsObject.verify(jwsVerifier)) {
        tokenMap.put("Result", 0);
        //将token数据转为json对象
        JSONObject jsonObject = payload.toJSONObject();
        //将token数据存入map中
        tokenMap.put("Data", jsonObject);
        //判断token是否过期
        if (jsonObject.containsKey("exp")) {
            //获取token保存的过期时间
            Long expTime = Long.valueOf(jsonObject.get("exp").toString());
            //获取当前时间戳
            Long nowTime = DateUtils.getTime();
            //判断是否过期
            if (nowTime > expTime) {
                //清除token信息,将其标志为过期
                tokenMap.clear();
                tokenMap.put("Result", 2);
            }
        }
    } else {
        //将token标志为不合法
        tokenMap.put("Result", 1);
    }
    return tokenMap;
}

//从token获取相关参数
public static Object get(String token, RSAKey rsaJwk ,String fieldName){
    try {
        Map<String, Object> validMap = JwtUtils.validToken(token,rsaJwk);
        JSONObject jsonObject = (JSONObject) validMap.get("Data");
        if (jsonObject.get(fieldName) == null){
            return "该参数不存在";
        }else{
            return jsonObject.get(fieldName);
        }
    }catch (ParseException e){
        e.printStackTrace();
    }catch (JOSEException e){
        e.printStackTrace();
    }
    return null;
}

}

### 使用非对称加密实现Token鉴权 在现代Web应用程序中,使用非对称加密技术可以有效提高Token的安全性和可靠性。通过公钥/私钥机制,可以在客户端和服务端之间建立安全通信通道。 #### 非对称加密原理概述 非对称加密算法基于一对密钥——公钥和私钥。其中,公钥用于加密数据,而私钥则用来解密这些被加密的数据。这种特性使得非对称加密非常适合于身份验证场景,在此过程中,服务端会生成一对密钥并将公钥分发给客户端[^1]。 当涉及到Token鉴权时,通常采用JSON Web Token (JWT)标准格式作为载体。JWT由三部分组成:头部、载荷以及签名。为了增强安全性,可以通过非对称加密的方式创建签名,从而防止篡改并确认发送者的真实性[^2]。 #### 实现步骤说明 以下是利用Java环境下的`hutool-crypto`库与`java-jwt`库相结合的方式来展示如何实施这一过程: 1. **引入必要的Maven依赖** ```xml <!-- hutool-crypto --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-crypto</artifactId> <version>5.7.16</version> </dependency> <!-- java-jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency> ``` 2. **编写签发Token的服务端代码** ```java import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; public class JwtService { private static final String PRIVATE_KEY = "your_private_key_here"; public String createJwt(String userId){ RSA rsa = new RSA(null, PRIVATE_KEY); Algorithm algorithm = Algorithm.RSA256(rsa.getPublicKey(), rsa.getPrivateKey()); return JWT.create() .withClaim("userId", userId) .sign(algorithm); } } ``` 3. **编写验证Token的服务器端逻辑** ```java import cn.hutool.crypto.asymmetric.KeyType; import cn.hutool.crypto.asymmetric.RSA; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.interfaces.DecodedJWT; public class JwtValidator { private static final String PUBLIC_KEY = "your_public_key_here"; public boolean verifyJwt(String token) throws Exception{ RSA rsa = new RSA(PUBLIC_KEY, null); Algorithm algorithm = Algorithm.RSA256((RSA.PublicKey)rsa.getKey(KeyType.PublicKey), null); JWTVerifier verifier = JWT.require(algorithm).build(); DecodedJWT jwt = verifier.verify(token); // 进一步处理解析后的token信息... System.out.println(jwt.getClaims()); return true; } } ``` 上述示例展示了如何在一个典型的Spring Boot项目中集成非对称加密来进行Token鉴权的过程。需要注意的是,在实际部署之前还需要考虑更多细节问题,比如异常捕获、过期时间设置等[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值