JWT

2023-10-26

1 常见的认证机制

1.1 HTTP Basic Auth

​ HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth

1.2 Cookie Auth

​ Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删除。但可以通过修改cookie 的expire time使cookie在一定时间内有效;

cookie

1.3 OAuth

​ OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。

​ OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容

下面是OAuth2.0的流程:

OAuth

​ 这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合拥有自有认证权限管理的企业应用。

1.4 Token Auth

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

Token Auth

Token Auth的优点

Token机制相对于Cookie机制又有什么好处呢?

  • 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输.
  • 无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
  • 更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服务端只要提供API即可.
  • 去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.
  • 更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
  • CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
  • 性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.
  • 不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
  • 基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).

2 基于JWT的Token认证机制实现

2.1 什么是JWT

​ JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户(客户端)和服务器之间传递安全可靠的信息。 token==》令牌(字符串)

2.2 JWT组成

一个JWT实际上就是一个字符串,它由三部分组成: 头部、载荷与签名。

头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。

{"typ":"JWT","alg":"HS256"}

在头部指明了签名算法是HS256算法。 我们进行BASE64编码

http://tool.oschina.net/encrypt?type=3

http://base64.xpcha.com/,

编码后的字符串如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

小知识:Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。JDK 中提供了非常方便的 BASE64EncoderBASE64Decoder,用它们可以非常方便的完成基于 BASE64 的编码和解码

载荷(playload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

(1)标准中注册的声明(建议但不强制使用)

iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 用户ID

(2)公共的声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

(3)私有的声明( 自定义)

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

这个指的就是自定义的claim。比如前面那个结构举例中的admin和name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

定义一个payload:

{"sub":"1234567890","name":"John Doe","admin":true}

然后将其进行base64编码,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

签名(signature)

jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)

payload (base64后的)

secret:秘钥 自定义的(打死也不能告诉别人)

这个部分需要base64编码后的header和base64编码后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

3 Java的JJWT实现JWT

3.1 什么是JJWT

​ JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。

3.2 JJWT快速入门

3.2.1 token的创建

(1)创建maven工程,引入依赖

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>

(2)创建类CreateJwtTest,用于生成token

public class CreateJwtTest {

    public static void main(String[] args) {

        JwtBuilder builder= Jwts.builder().setId("888")
                .setSubject("小白")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256,"itcast");
        System.out.println( builder.compact() );

    }
}

setIssuedAt用于设置签发时间

signWith用于设置签名秘钥

(3)测试运行,输出如下:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTM0NTh9.gq0J-cOM_qCNqU_s-d_IrRytaNenesPmqAIhQpYXHZk

再次运行,会发现每次运行的结果是不一样的,因为我们的载荷中包含了时间。

3.2.2 token的解析

​ 我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。

创建ParseJwtTest

public class ParseJwtTest {

    public static void main(String[] args) {
        String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTM0NTh9.gq0J-cOM_qCNqU_s-d_IrRytaNenesPmqAIhQpYXHZk";
        Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(token).getBody();
        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        System.out.println("IssuedAt:"+claims.getIssuedAt());
    }
}

试着将token或签名秘钥篡改一下,会发现运行时就会报错,所以解析token也就是验证token

3.2.3 token过期校验

有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添加一个过期时间。

创建CreateJwtTest2

public class CreateJwtTest2 {

    public static void main(String[] args) {

        //为了方便测试,我们将过期时间设置为1分钟
        long now = System.currentTimeMillis();//当前时间
        long exp = now + 1000*60;//过期时间为1分钟
        JwtBuilder builder= Jwts.builder().setId("888")
                .setSubject("小白")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256,"itcast")
          		.setExpiration(new Date(exp));
        System.out.println( builder.compact() );
    }
}

setExpiration 方法用于设置过期时间

修改ParseJwtTest

public class ParseJwtTest {

    public static void main(String[] args) {
        String compactJws="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTY1NjksImV4cCI6MTUyMzQxNjYyOX0.Tk91b6mvyjpKcldkic8DgXz0zsPFFnRgTgkgcAsa9cc";
        Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJws).getBody();
        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
        System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
        System.out.println("当前时间:"+sdf.format(new Date()) );

    }
}

测试运行,当未过期时可以正常读取,当过期时会引发io.jsonwebtoken.ExpiredJwtException异常。

Exception in thread "main" io.jsonwebtoken.ExpiredJwtException: JWT expired at 2018-06-08T21:44:55+0800. Current time: 2018-06-08T21:44:56+0800
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:365)
	at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
	at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:518)
	at cn.itcast.demo.ParseJwtTest.main(ParseJwtTest.java:13)

3.2.4 自定义claims

我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims 创建CreateJwtTest3

public class CreateJwtTest3 {

    public static void main(String[] args) {

        //为了方便测试,我们将过期时间设置为1分钟
        long now = System.currentTimeMillis();//当前时间
        long exp = now + 1000*60;//过期时间为1分钟
        JwtBuilder builder= Jwts.builder().setId("888")
                .setSubject("小白")
                .setIssuedAt(new Date())
                .signWith(SignatureAlgorithm.HS256,"itcast")
                .setExpiration(new Date(exp))
                .claim("roles","admin")
                .claim("logo","logo.png");
        System.out.println( builder.compact() );
    }
}

修改ParseJwtTest

public class ParseJwtTest {

    public static void main(String[] args) {
        String compactJws="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1MjM0MTczMjMsImV4cCI6MTUyMzQxNzM4Mywicm9sZXMiOiJhZG1pbiIsImxvZ28iOiJsb2dvLnBuZyJ9.b11p4g4rE94rqFhcfzdJTPCORikqP_1zJ1MP8KihYTQ";
        Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJws).getBody();
        System.out.println("id:"+claims.getId());
        System.out.println("subject:"+claims.getSubject());
        System.out.println("roles:"+claims.get("roles"));
        System.out.println("logo:"+claims.get("logo"));

        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

        System.out.println("签发时间:"+sdf.format(claims.getIssuedAt()));
        System.out.println("过期时间:"+sdf.format(claims.getExpiration()));
        System.out.println("当前时间:"+sdf.format(new Date()) );

    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JWT 的相关文章

  • JenKins结合cppcheck及cpplint进行代码风格及静态代码检测

    JenKins结合cppcheck及cpplint 最近公司需要在Jenkins上安装cppcheck及cpplint进行代码风格及静态代码检测 这里记录下过程 前提条件 安装了Jenkins 步骤如下 第一步 安装cppcheck并配置环
  • [Linux] yum和apt-get用法及区别

    一般来说著名的linux系统基本上分两大类 1 RedHat系列 Redhat Centos Fedora等 2 Debian系列 Debian Ubuntu等 RedHat 系列 1 常见的安装包格式 rpm包 安装rpm包的命令是 rp
  • vs2019调试时中文乱码解决办法

    vs2013 vs2019系列文章目录 文章目录 vs2013 vs2019系列文章目录 问题描述 一 解决 解决方法1 在我机器上仍然未解决 解决方法2 在我机器上可行 调试时中文显示效果 问题描述 vs2019调试时中文乱码 但是在vs
  • except Exception as e作用

    小记 今天在查看poc时 发现这段代码不理解 所以B站搜索了一下 把别人讲的内容爬了一下 coding utf 8 a int input 请输入数字0 try if a 0 print a except Exception as e 作用
  • Redis高可用集群(哨兵、集群)

    文章目录 前言 一 主从复制 1 1 主从复制的作用 1 2 主从复制流程 1 3 主从复制搭建 二 哨兵模式 2 1 哨兵模式的作用 2 2 哨兵结构的组成 2 3 故障转移机制 2 4 哨兵模式搭建 三 集群模式 3 1 集群的作用 3
  • shell 脚本调试工具

    bashdb 是一个类似GDB的脚本调试软件 具有断点 单步执行 观察变量等功能 安装方法 sudo apt get install bashdb bashdb 使用方法 bashdb options script name script
  • vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件

    CommTable vue table组件
  • 多人连线的枪战游戏

    Simple Blueprint Multiplayer 是一个完全由 蓝图 和 UMG 界面 编写的游戏 可以作为如何使用蓝图的 Session Nodes 打造游戏中的多人部分的使用示例 这里有一个主菜单 一个服务器列表 以及一个简单的
  • java如何将null转化为空串也就是empty

    java如何将null转化为空串也就是empty 前言 在说转换之前 简单说一下它们之间的区别 如下 1 null不指向任何对象 相当于没有任何值 而 代表一个长度为0的字符串 2 null不分配内存空间 而 会分配内存空间 那如何将nul
  • HTTP 2.0 与HTTP1.1的差别

    前面的话 在说HTTP2 0前 先说一说发展到HTTP1 1做了哪些升级 推荐好文 一文读懂HTTP 2及HTTP 3特性 HTTP1 1的升级 目前使用最广泛的HTTP1 1做了哪些重大升级 默认长连接 HTTP1 0也提供长连接 但是默
  • 拓扑排序(广度优先搜索实现)

    有向无环图可以用来表示各种事物的顺序 比如工作顺序 一些事情必须在另一些事情完成之后才能开始进行 那么 为了获得正确的工作顺序 一件事情开始之前 必须保证它的前置条件全部满足 就需要用到拓扑排序 拓扑排序其实就是在有向无环图中 只要存在边
  • nvm 查看所有可以下载node的版本

    nvm 查看所有可以下载node的版本 nvm list 命令 显示版本列表 nvm list 显示已安装的版本 同 nvm list installed nvm list installed 显示已安装的版本 nvm list avail
  • 三阶段提交协议(3PC)

    3PC 主要是为了解决两阶段提交协议的单点故障问题和缩小参与者阻塞范围 引入参与节点的超时机制之外 3PC把2PC的准备阶段分成事务询问 该阶段不会阻塞 和事务预提交 则三个阶段分别为CanCommit PreCommit DoCommit
  • codeforces 526D(kmp,数学)

    description One day Om Nom found a thread with n beads of different colors He decided to cut the first several beads fro
  • 内核体系结构和编译体系分析

    1 Linux操作系统体系结构 1 操作系统可以分为两个层次 内核空间和用户空间 内核和用户空间使用不同的保护地址空间 内核不能将用户空间传递的地址进行直接的操作 需要先转换 2 系统调用 内核空间管理设备资源 应用程序通过内核提供的内核调
  • 米家接入HomeKit系列三:HomeAssistant接入米家网关

    系列文章 米家接入HomeKit系列一 接入基本原理与开篇 米家接入HomeKit系列二 通过群辉NAS的Docker搭建HomeAssistant 米家接入HomeKit系列三 HomeAssistant接入米家网关 米家接入HomeKi
  • 微信小程序--web-view--h5返回微信小程序

    1 配置微信小程序 web view 记得配置业务域名 微信公众平台配置业务域名 上线需要 1 1 建议微信小程序里单独用一个页面打开
  • debug

    1 在DOS提示符下 进入Debug程序 2 详细记录每一步所用的命令 以及查看结果的方法和具体结果 3 现有一个双字加法源程序如下 其中存在错误 现假设已汇编 连结生成了可执行文件HB EXE 存放在d MASM目录下 请使用Debug对
  • argmax与max的区别

    y max f x 表示y是函数f x 的最大值 y argmax f x 表示y为函数f x 取得最大值时 参数x的值 例 f x x3 x的取值范围是 0 1 2 3 y max f x 27 y argmax f x 3
  • AcWing 907. 区间覆盖 贪心

    AcWing 907 区间覆盖 给定N个闭区间 ai bi 以及一个线段区间 s t 请你选择尽量少的区间 将指定线段区间完全覆盖 输出最少区间数 如果无法完全覆盖则输出 1 输入格式 第一行包含两个整数s和t 表示给定线段区间的两个端点

随机推荐

  • 数据分析中的统计与机器学习应用

    1 数据分析应用场景 数据分析场景 例如逛淘宝 后台一般会从以下几个方面对用户数据进行分析来 了解的一个产品的数据模型 1 Acquisition 获取用户 运营一件产品首先就需要获取用户 也就是推广 运营人员要分析自己产品的特性以及想要推
  • 一文看懂PCB助焊层跟阻焊层的区别与作用

    一文看懂PCB助焊层跟阻焊层的区别与作用 PCBworld 今天 阻焊层简介 阻焊盘就是soldermask 是指板子上要上绿油的部分 实际上这阻焊层使用的是负片输出 所以在阻焊层的形状映射到板子上以后 并不是上了绿油阻焊 反而是露出了铜皮
  • zookeeper 搭建集群

    待完善
  • 《计算机文化基础》22-23第一学期后十周教学计划(中国铁道出版社第三版)

    课程 任课教师 授课班级 编制时间 计算机文化基础 2022 10 28 授课日期 2022年 10月31日至 2022年 12月 16日 本课程总课时 28课时 已授课时 0 课时 尚余课时 28课时 本学期授课周 7周 本学期周课时 4
  • 超详细讲解!Android面试题集2021版,面试心得体会

    前言 Android常用知识体系是什么鬼 所谓常用知识体系 就是指对项目中重复使用率较高的功能点进行梳理 注意哦 不是Android知识体系 古语道 学而不思则罔 思而不学则殆 如果将做项目类比为 学 那么整理就可以类比为 思 在做项目过程
  • 文件包含漏洞

    一 文件包含函数 将外部文件的内容引入当前环境 include
  • 玩转Kali之初始化系统

    文章目录 下载镜像 安装系统 修改root密码 配置APT国内源 更新软件包 下载镜像 1 打开kali官网 https www kali org 安装系统 1 打开VirtualBox 2 选择新建虚拟机 1 输入虚拟机名称 2 选择安装
  • TopK问题的三种解法

    TopK问题是指从n个数据中取前K个数据 在生活中的应用也有很多 如游戏中xxx的排行榜前10名等 在这篇博客中我将主要利用堆去解决TopK问题 堆排序 首先我们需要建一个堆 然后我们再进行堆排序 排好序后直接取前K个就可以了 需要注意的是
  • Debian10iptables放行语法

    文章目录 1 基本语法 2 修改默认规则 3 实例 4 易错总结 1 基本语法 iptables A 链 匹配条件 j 动作 D 删除 p 协议 ACCEPT 放行 s 源ip地址 DROP 丢弃 d 目的ip地址 REJECT 拒绝 sp
  • java.util.EnumSet complementOf (EnumSet<E> s)方法具有什么功能呢?

    转自 java util EnumSet complementOf EnumSet lt E gt s 方法具有什么功能呢 下文笔者讲述EnumSet complementOf方法的功能简介说明 如下所示 EnumSet complemen
  • To Java程序员:切勿用普通for循环遍历LinkedList

    ArrayList与LinkedList的普通for循环遍历 对于大部分Java程序员朋友们来说 可能平时使用得最多的List就是ArrayList 对于ArrayList的遍历 一般用如下写法 public static void mai
  • 余弦定理实现新闻自动分类算法

    前言 余弦定理 这个在初中课本中就出现过的公式 恐怕没有人不知道的吧 但是另外一个概念 可能不是很多的人会听说过 他叫空间向量 一般用e表示 高中课本中有专门讲过这个东西 有了余弦定理和向量空间 我们就可以做许多有意思的事情了 利用余弦定理
  • Spring框架(三)Spring注解和获取Bean对象详解

    目录 一 什么是基于Java的Spring注解配置 具体注解的例子 二 更好的将Bean存储在Spring中 1 前置工作 在配置文件中设置Bean根路径 2 添加注解存储Bean对象 2 1 Controller 控制器存储 2 2 Se
  • Vue中 实现上一篇下一篇的功能

    效果 看下html页面 div class NewsDetails cont footer div img src assets img newsDetail 公共 更多2 1 png alt span 上一篇 lastTitle span
  • 软件开发 文档 质量

    1 在撰写API文档时 如果某个API的性能 时间性能 内存性能 特别低 应该在文档里详细列出 如此做的好处是 1 1 有助于客户在设计阶段 采用正确 高效的方案 1 2 对于开发这个API的team 可以减轻维护压力 明确责任 因为在文档
  • 中文同义句在线转换器 - 中文同义句转换器软件

    在线同义句转换器 中文同义句在线转换器 中文同义句转换器软件 made in Japan 祝你学习进步 更上一层楼 请记得采纳 谢谢 同义句转换器 1 I d like to go to the beach on vacation beca
  • 【1803. 统计异或值在范围内的数对有多少】

    来源 力扣 LeetCode 描述 给你一个整数数组 nums 下标 从 0 开始 计数 以及两个整数 low 和 high 请返回 漂亮数对 的数目 漂亮数对 是一个形如 i j 的数对 其中 0 lt i lt j lt nums le
  • 2019年黑马新版Java学习路线图(内含大纲+视频+工具+书籍+面试)面试必看!

    非常好的java学习路线 伴有配套资源 面试必看 黑马程序员 http bbs itheima com thread 386464 1 1 html
  • LEVELDB介绍

    基本信息 特性 keys 和 values 是任意的字节数组 数据按 key 值排序存储 调用者可以重载函数来重写排序顺序 提供基本的 Put key value Get key Delete key Batch 操作 多个更改可以在一个原
  • JWT

    1 常见的认证机制 1 1 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password 简言之 Basic Auth是配合RESTful API 使用的最简单的