Jwt新手入门教程

Jwt的新手入门教程

1.Jwt究竟是什么东东?

​ 先贴官网地址:JSON Web Tokens – jwt.io

Jwt新手入门教程

​ 再贴官方的定义:

What is JSON Web Token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.

​ 我的理解总结: Jwt全称是 Json Web Token,顾名思义就是一种通过Json方式来传输的令牌,并且他最大的特点就是 signed tokens,签发者可以使用各种的加密方式对信息进行签名,更重要的是Jwt还能验证token是否被篡改或者token是否正确。当然了,这种方式注定是不安全的。我们很容易地就可以在官网得到这一结论。

Jwt新手入门教程

​ 可以看到,只要我们获得token字符串,就可以获取到里面的大部分信息,除了签名的密钥。

所以Jwt简单来说,就是简单地存储部分不那么重要的信息,通过Json,对客户端进行验证的一种方式。

2.Jwt的组成

​ 从官网的Debugger界面,我们可以得知,Jwt由三部分组成。

Jwt新手入门教程

  • 第一部分: Header,Header通常由令牌的类型和加密的算法组成,也就是
{
  "alg": "HS256",
  "typ": "JWT"
}

这个Header的含义就是”alg”–Algorithm(算法) 是HS256。

  • 第二部分: Payload,这部分主要是记录我们所存储的简单且不重要的信息。例如:用户名,过期时间,用户id等等。
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

但是要注意的是,Payload记录的这些信息是 完全公开的,所以千万不能把用户或者系统的敏感数据放到Payload中,Payload只是负责记录简单信息,并不具备加密的功能。

  • 第三部分: Signature, 签名里是由三部分组成,Header的Base64编码,Payload的Base64编码,还有secret,然后通过指定的加密方式,例如HS256,进行加密后得出的字符串。
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

可以说这部分是Jwt的重点,因为他承担着两个作用,第一个: 验证JwtToken在传输过程中没有受到篡改 第二个: 验证签发人的身份

​ 详细说一下这两个作用。

验证JwtToken在传输过程中没有受到篡改,这个原理就比较好理解,因为Signature中有一个字符串,也就是 secret,这个secret是由我们来设置的,相当于私钥,只有我们自己才知道,别人是不知道的。那么在后续验证过程中,只要我们自己生产的Token与客户端传来的Token进行比对,如果一致那就证明该Token没有受到篡改,反之则证明客户端传来的Token是非法的。

验证签发人的身份,其实第二个作用是从第一个作用中展现而来的,因为如果能证明Token在传输过程中没有受到篡改,那就更加说明服务端是这个签名的签发者,因为 只有签发者才知道私钥

​ 其实secret我们也可以认为是盐(salt), 我们知道如果单纯地在数据库中存储明文密码,或者是只经过一重MD5加密的密码,是非常的不安全,因为就算是经过MD5加密,仍然可以通过暴力穷举的方式来进行破解,可是如果在用户密码的基础上,加上我们生成的随机或固定的字符串,然后再进行加密,那么安全程度会大大提升。

​ 如果不知道盐(salt)的童鞋,可以去bind搜索一下相关资料,其实理解起来就是用户密码+我们设置的随机或固定字符串再进行多重加密。

3.编码实现

​ 我们来创建这几个类。

Jwt新手入门教程

配置类:InterceptorConfig

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authenticationInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login");
    }

    @Bean
    public JwtInterceptor authenticationInterceptor() {
        return new JwtInterceptor();
    }

}

控制类: UserController

@RestController
public class UserController {

    @PostMapping("/login")
    public Map login(@RequestBody User user) {

        Map map = new HashMap<>();
        String username = user.getUsername();
        String password = user.getPassword();
        // 省略 账号密码验证
        // 验证成功后发送token
        String token = JwtUtil.sign(username, password);
        if (token != null) {
            map.put("code", "200");
            map.put("message", "认证成功");
            map.put("token", token);
            return map;
        }
        map.put("code", "403");
        map.put("message", "认证失败");
        return map;
    }

    @GetMapping(value = "/api/test")
    public String get(){
        System.out.println("执行了get请求");
        return "success";
    }
}

服务类:UserService

@Service
public class UserService {

    public String getPassword(){

        return "admin";
    }
}

实体类 User

@Data
public class User {

    private String username;
    private String password;

}

自定义拦截器类 JwtIntercepter

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Autowired
    UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从 http 请求头中取出 token
        String token = request.getHeader("token");
        // 如果请求不是映射到方法直接通过
        if(!(handler instanceof HandlerMethod)){
            return true;
        }
        if (token != null){
            String username = JwtUtil.getUserNameByToken(request);
            // 这边拿到的 用户名 应该去数据库查询获得密码,简略,步骤在service直接获取密码
            boolean result = JwtUtil.verify(token,username,userService.getPassword());
            if(result){
                System.out.println("通过拦截器");
                return true;
            }
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

Jwt工具类 JwtUtil

public class JwtUtil {

    // Token一天后过期
    public static final long EXPIRE_TIME = 1000 * 60 * 60 * 24;

    //检验Token是否正确
    public static boolean verify(String token, String username, String secret) {
        try {
            // 设置加密算法
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim("username", username)
                    .build();
            // 效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    public static String sign(String username, String secret) {
        //现在系统的时间 + 一天
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //对密码进行加密
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create()
                .withClaim("username", username)
                .withExpiresAt(date)
                .sign(algorithm);
    }

    public static String getUserNameByToken(HttpServletRequest request)  {
        String token = request.getHeader("token");
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("username")
                .asString();
    }

}

具体代码,我上传到github上:Alickx/JwtTokenDemo: JwtDemo代码 (github.com)

这里代码的secret则是用户的密码。

我们先通过PostMan向 /login接口发送我们的账号密码,得到Jwt根据我们的账号密码生成的token。

{
    "code": "200",
    "message": "认证成功",
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIzMTg1NjksInVzZXJuYW1lIjoiYWRtaW4ifQ.c_m3z11UOcFcS_hZN9KNlidzZ2j6y_Ugkb9awHQ3FGY"
}

Jwt新手入门教程

这里认证成功后,服务器如果不经过我们其他的存储操作,是 不会对生成的token进行持久化或其他控制的,所以一旦签发出去,这个token串就会变成无状态了。

​ 接着,我们访问一下我们的api测试接口,因为我们在config里配置了全局拦截器,且重写了HandlerInterceptor类,除了/login路径,其他全路径都需要请求的Header(请求头)中带有token字段,且需验证token成功后才会允许访问,否则进行拦截。

Jwt新手入门教程

4.管理JwtToken的状态

​ 要做到管理JwtToken的状态,我们可以通过把token存储到Redis数据库中,通过设置key的过期时间,就可以做到对Jwt的过期操作,同时也能够对Token进行续签,失效等等操作。这部分先不去仔细探究,有个思路就可以了。具体的编码实现我相信也不难。

本文中所有的代码均已上传到github上,如有需要请下载。

Alickx/JwtTokenDemo: JwtDemo代码 (github.com)

JwtTokenDemo (gitee.com)

Original: https://www.cnblogs.com/Alickx/p/15318106.html
Author: Alickx
Title: Jwt新手入门教程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/643190/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • redis启动报无权限

    设置一下SELINUX 关闭SElinux 查看selinux状态 [root@localhost ~]# getenforce Enforcing 表示启动 临时关闭 [root…

    技术杂谈 2023年7月25日
    098
  • python3GUI–用Tk开发一款恶搞蓝屏软件(附源码)

    一.准备工作 1.Tkinter 2.科普-电脑蓝屏 二.预览 1.蓝屏-win10、win11(中文版) 2.蓝屏-win10、win11(英文版) 3.Windows其他版本(…

    技术杂谈 2023年6月21日
    0137
  • 微信小程序性能优化

    作者:孟繁贵 Email:meng010387@126.com 期待共同进步! Original: https://www.cnblogs.com/mengfangui/p/163…

    技术杂谈 2023年5月31日
    078
  • java多线程

    多线程: 多线程是指程序中包含多个执行流,即在-个程序中可以同时运行多个不同的线程来执行不同的任务。 多线程的好处: 可以提高 CPU 的利用率。在多线程程序中,一个线程必须等待的…

    技术杂谈 2023年7月24日
    065
  • DelayQueue详解

    DelayQueue介绍 【1】DelayQueue 是一个支持延时获取元素的阻塞队列, 内部采用优先队列 PriorityQueue 存储元素,同时元素必须实现 Delayed …

    技术杂谈 2023年7月24日
    078
  • Fluent-Validator 业务校验器

    在互联网行业中,基于Java开发的业务类系统,不管是服务端还是客户端,业务逻辑代码的更新往往是非常频繁的,这源于功能的快速迭代特性。在一般公司内部,特别是使用Java web技术构…

    技术杂谈 2023年7月11日
    082
  • 一款吊炸天的AI图片增强工具!

    背景 如果你工作中需要制作文档,PPT,或者给文章配图,或者需要制作视频。一定会有在网上寻找图片素材的经历。 但网上的图质量参差不一,有时候找到了喜欢的图,但是质量不行,分辨率太低…

    技术杂谈 2023年7月11日
    0104
  • ML/NLP中的一些术语/公式备忘录

    CCGcombinatory categorial grammar组合范畴语法 在数学中,误差函数(也称之为高斯误差函数,error function or Gauss error…

    技术杂谈 2023年6月21日
    091
  • Vue笔记:Vue3 Table导出为Excel

    1、安装 2、添加插件 在 src 目录下创建一个文件(vendor) 并添加Blob.js和Export2Excel.js,对 Export2Excel.js 添加了一段代码,可…

    技术杂谈 2023年5月31日
    0101
  • Java — 面向对象

    简介:类是对事物的一种描述,对象则为具体存在的事物。 类的定义: public class 类名 { // 成员变量 访问修饰符 数据类型 变量名; … // 成员方法 访问修…

    技术杂谈 2023年7月11日
    064
  • 英特尔® VTune™ Profiler 用户指南——程序性能异常检测分析

    https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/analyze-perfo…

    技术杂谈 2023年5月31日
    0111
  • Anaconda, PyTorch, CUDA Driver, PyCharm 安装与配置

    安装Anaconda(2022.05) 最新版本 https://www.anaconda.com/历史版本 https://repo.anaconda.com/archive/ …

    技术杂谈 2023年7月24日
    087
  • delphi和go以及其他语言基于结构的数据序列和还原

    delphi和go以及其他语言基于结构的数据序列和还原 数据序列基于结构,是跨语言、平台能够实现数据标准的基础。 GO基于结构的序列 DELPHI基于结构的序列 Original:…

    技术杂谈 2023年5月30日
    091
  • html大文件分段传输

    总结一下大文件分片上传和断点续传的问题。因为文件过大(比如1G以上),必须要考虑上传过程网络中断的情况。http的网络请求中本身就已经具备了分片上传功能,当传输的文件比较大时,ht…

    技术杂谈 2023年5月30日
    0117
  • NYOJ127 星际之门(一)【定理】

    描写叙述 公元3000年,子虚帝国统领着N个星系,原先它们是靠近光束飞船来进行旅行的,近来,X博士发明了星际之门,它利用虫洞技术。一条虫洞能够连通随意的两个星系,使人们不必再待待便…

    技术杂谈 2023年5月31日
    0109
  • Java日志框架

    流行的日志框架 JUL Log4j JCL SLF4j Logback Log4j2 总结 依赖导入总结 日志门面 日志实现 桥接器、适配器理解 使用logback + slf4j…

    技术杂谈 2023年7月11日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球