Comenzando con JWT, ¿se puede descifrar jwt?

JWT

¿Qué es JWT?

JSON Web Token, a través de firmas digitales, utiliza objetos JSON como portadores para transmitir información de forma segura entre diferentes terminales de servicio

  • Sitio web oficial: https://jwt.io/
  • SDK: https://jwt.io/libraries (incluido Java y varios idiomas)
  • SDK de Java (obtenido del enlace SDK anterior): https://github.com/auth0/java-jwt (hay muchos tipos de SDK de Java, este es uno de ellos)
  • Puede elegir el SDK de acuerdo con sus propias preferencias. Diferentes SDK tienen diferentes diseños de API, por lo que, naturalmente, habrá buenos o malos.
  • El SDK utilizado en este proyecto también es uno de los recomendados oficialmente (es mejor elegir el oficial que el desconocido)

¿Para qué sirven los JWT?

El escenario más común de JWT es la autenticación de autorización. Una vez que el usuario inicia sesión, cada solicitud posterior contendrá JWT. Antes de que se procese cada solicitud de usuario, el sistema primero debe realizar la verificación de seguridad de JWT y luego procesarla después de pasar.

Composición de JWT

JWT consta de 3 partes, concatenadas con .

el formato esHeader.Payload.Signature

  • Encabezado (información del encabezado)
{
    
    
  'typ': 'JWT',
  'alg': 'HS256'
}

Incluyendo type typ y algoritmo alg, el tipo es JWT codificado, el algoritmo puede ser determinado por usted mismo, aquí hay un ejemplo de HS256

  • Carga útil
实际的有效数据,你要传的业务数据,例如:


  • Firma
Signature是这么算出来的?

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'your_secret');

说明:
1、header和payload先用base64加密用点链接起来,再用header里alg所指定的算法计算摘要
2、your_secret 就是秘钥,加密方和解密方共同知道的,解密的时候要用

Reponer

Cuando obtiene una cadena jwt (es decir, la cadena de tres segmentos), ¿qué puede saber?

Para xxx.yyy.zzz, puede saber

  • xxx, puedes descifrar xxx con base64
  • yyy, pensé que base64 no se podía descifrar, pero resultó estar bien. Además, también encontré que no se podía descifrar. Puede ser que lo cifré adicionalmente.
  • zzz, no se puede descifrar en base64

Nota : no pegue todo el párrafo en él y descifrelo con base64, pero divídalo en secciones, de lo contrario, es posible que no se descifre.

ejemplo

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZWFjaGVyIjp7Im5hbWUiOiJNaXNzIExlZSJ9LCJzZXgiOnRydWUsIm5hbWUiOiJTdG9uZSIsImNvdXJzZUxpc3QiOlt7Im5hbWUiOiJNYXRoIiwiY3JlZGl0cyI6NH0seyJuYW1lIjoiRW5nbGlzaCIsImNyZWRpdHMiOjN9XSwiZXhwIjoxNjkxNDExMzcyLCJhZ2UiOjIwfQ.C2LJfyeeS2E0tpS12o-MnQWvn3B7ecK_ul3kudpiAPE

注意一定要分段粘贴进去进行base64解密,不要一整个整体,本例子没有问题,有些别的例子会出现yyy部分不能解密的情况!!!

base64解密第一段:{"typ":"JWT","alg":"HS256"}
base64解密第一段:{"teacher":{"name":"Miss Lee"},"sex":true,"name":"Stone","courseList":[{"name":"Math","credits":4},{"name":"English","credits":3}],"exp":1691411372,"age":20}
base64解密第一段:(乱码,看来是解密不了)

ejemplo java

De hecho, en el proceso de uso real, Java como backend solo necesita escribir y analizar jwt. Para la encapsulación, esto es lo que debe hacer el frontend.

package com.wyf.test.jwt;

import io.jsonwebtoken.*;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

public class JWTTest {
    
    
    private static final String MY_SECRET = "xAy23hz23YK";// 加解密用的秘钥

    public static void main(String[] args) throws InterruptedException {
    
    
        String jwtString = testGetJwtString();
        //Thread.sleep(4*1000);// 模拟超市的情况是否能检查出来
        System.out.println("\n-------------------\n");
        testParseJwtString(jwtString);
    }

    // 得到加密的字符串,这个一般来说不是Java写的,肯定是前端人员写的,JS(react/vue等)
    public static String testGetJwtString() {
    
    
        /*
         格式:Header.Payload.Signature
         header的格式是:
         {
         'typ': 'JWT',
         'alg': 'HS256'
         }
         其中类型typ写死,alg可选,这里选HS256算法

         Payload 是实际的数据
         Signature的计算方式如下(参考如下用JS写的伪代码):
         var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
         var signature = HMACSHA256(encodedString, 'your_secret');

         其中 your_secret 就是秘钥,加密方和解密方共同知道的,解密的时候要用
         */

        // 设置 token 有效期
        long tokenLifespan = 3 * 1000; // 30 秒
        Date expireDateTime = new Date(System.currentTimeMillis() + tokenLifespan);

        // 用 Java 中引入的 JWT 包里的 API
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtString = jwtBuilder
                // header
                .setHeaderParam("typ", "JWT").setHeaderParam("alg", "HS256")
                // payload (claim 其实就是payload的意思,就是你要传的数据)
                .setClaims(prepareMapPayloadData())
                // 可选,设置 token 有效期
                .setExpiration(expireDateTime)
                // signature (解密的时候用的secret不对的话会抛出signature无法匹配的异常:io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature.)
                .signWith(SignatureAlgorithm.HS256, MY_SECRET)
                // 用点连接起来
                .compact();

        System.out.println("jwtString:" + jwtString);
        System.out.println("token duration(Sec):" + (tokenLifespan / 1000));
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        System.out.println("expireDateTime:" + simpleDateFormat.format(expireDateTime));
        return jwtString;
    }

    // 我在想这个方法根本就不需要返回payload里的值,如果使用JWT,仅仅是validate一下signature是不是正确的、达到鉴权效果就可以了
    public static Object testParseJwtString(String jwtString) {
    
    
        JwtParser jwtParser = Jwts.parser();
        // 设置解密用的秘钥(解密的时候用的secret不对的话会抛出signature无法匹配的异常)
        jwtParser.setSigningKey(MY_SECRET);

        // parse 的时候就会校验签名,不正确的时候会从这行抛出异常,也会校验token是否超时!如果超时爆出
        // Exception in thread "main" io.jsonwebtoken.ExpiredJwtException: JWT expired at 2023-08-07T18:59:42Z. Current time: 2023-08-07T18:59:44Z, a difference of 2416 milliseconds.  Allowed clock skew: 0 milliseconds.
        Jwt parse = jwtParser.parse(jwtString);
        Header header = parse.getHeader();
        Object body = parse.getBody();// 其API是设计成用Object接收的
        System.out.println("header: " + (header != null ? header.getClass().toString() + ", " + header : "null"));
        System.out.println("body: " + (body != null ? body.getClass().toString() + ", " + body : "null"));

        return body;
    }



    /**
     * method to convert object to a map
     * @param obj
     * @return
     * @throws IllegalAccessException
     */
    public static Map<String, Object> getObjectToMap(Object obj) throws IllegalAccessException {
    
    
        Map<String, Object> map = new HashMap<String, Object>();
        Class<?> cla = obj.getClass();
        Field[] fields = cla.getDeclaredFields();
        for (Field field : fields) {
    
    
            field.setAccessible(true);
            String keyName = field.getName();
            Object value = field.get(obj);
            if (value == null)
                value = "";
            map.put(keyName, value);
        }
        return map;
    }

    public static Map<String, Object> prepareMapPayloadData() {
    
    
        Map<String, Object> objectToMap;
        try {
    
    
            objectToMap = getObjectToMap(preparePayloadData());
        } catch (IllegalAccessException e) {
    
    
            throw new RuntimeException(e);
        }
        System.out.println("payload map: " + objectToMap);
        return objectToMap;
    }

    public static Student preparePayloadData() {
    
    
        List<Course> courseList = new ArrayList<Course>();
        Course course1 = new Course();
        course1.setName("Math");
        course1.setCredits(4);
        Course course2 = new Course();
        course2.setName("English");
        course2.setCredits(3);
        courseList.add(course1);
        courseList.add(course2);

        Teacher teacher = new Teacher();
        teacher.setName("Miss Lee");

        Student student = new Student();
        student.setName("Stone");
        student.setAge(20);
        student.setSex(true);
        student.setTeacher(teacher);
        student.setCourseList(courseList);

        return student;
    }
    public static class Student {
    
    
        private String name;
        private Integer age;
        private Boolean sex;

        private Teacher teacher;

        private List<Course> courseList;

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }

        public Integer getAge() {
    
    
            return age;
        }

        public void setAge(Integer age) {
    
    
            this.age = age;
        }

        public Boolean getSex() {
    
    
            return sex;
        }

        public void setSex(Boolean sex) {
    
    
            this.sex = sex;
        }

        public Teacher getTeacher() {
    
    
            return teacher;
        }

        public void setTeacher(Teacher teacher) {
    
    
            this.teacher = teacher;
        }

        public List<Course> getCourseList() {
    
    
            return courseList;
        }

        public void setCourseList(List<Course> courseList) {
    
    
            this.courseList = courseList;
        }
    }

    public static class Teacher {
    
    
        private String name;

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }
    }
    public static class Course {
    
    
        private String name;
        private Integer credits;

        public String getName() {
    
    
            return name;
        }

        public void setName(String name) {
    
    
            this.name = name;
        }

        public Integer getCredits() {
    
    
            return credits;
        }

        public void setCredits(Integer credits) {
    
    
            this.credits = credits;
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/w8y56f/article/details/132154222
Recomendado
Clasificación