现在API越来越流行,如何安全保护这些API? JSON Web Tokens(JWT)能提供基于JSON格式的安全认证。它有以下特点:

  • JWT是跨不同语言的,JWT可以在 .NET, Python, Node.js, Java, PHP, Ruby, Go, JavaScript和Haskell中使用
  • JWT是自我包涵的,它们包含了必要的所有信息,这就意味着JWT能够传递关于它自己的基本信息,比如用户信息和签名等。
  • JWT传递是容易的,因为JWT是自我包涵,它们能被完美用在HTTP头部中,当需要授权API时,你只要通过URL一起传送它既可。

JWT易于辨识,是三段由小数点组成的字符串:

aaaaaaaaaa.bbbbbbbbbbb.cccccccccccc

这三部分含义分别是header,payload, signature

Header

头部包含了两个方面:类型和使用的哈希算法(如HMAC SHA256):

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

对这个JSON字符进行base64encode编码,我们就有了首个JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload

JWT的第二部分是payload,也称为 JWT Claims,这里放置的是我们需要传输的信息,有多个项目如注册的claim名称,公共claim名称和私有claim名称。

注册claim名称有下面几个部分:

  • iss: token的发行者
  • sub: token的题目
  • aud: token的客户
  • exp: 经常使用的,以数字时间定义失效期,也就是当前时间以后的某个时间本token失效。
  • nbf: 定义在此时间之前,JWT不会接受处理。开始生效时间
  • iat: JWT发布时间,能用于决定JWT年龄
  • jti: JWT唯一标识. 能用于防止 JWT重复使用,一次只用一个token;如果签发的时候这个claim的值是“1”,验证的时候如果这个claim的值不是“1”就属于验证失败

公共claim名称用于定义我们自己创造的信息,比如用户信息和其他重要信息。

私有claim名称用于发布者和消费者都同意以私有的方式使用claim名称。

下面是JWT的一个案例:

{
"iss": "scotch.io",
"exp": 1300819380,
"name": "Chris Sevilleja",
"admin": true
}

签名

JWT第三部分最后是签名,签名由以下组件组成:

  • header
  • payload
  • 密钥

下面是我们如何得到JWT的第三部分:

var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload); HMACSHA256(encodedString, 'secret');

这里的secret是被服务器签名,我们服务器能够验证存在的token并签名新的token。

TWT支持的算法有:

============================================================================================================

以上是官网的理论部分,下面会有提供一些实例:

首先 导入 依赖:

<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.2.0</version>
</dependency>

1, 指定加密算法:

//HMAC
Algorithm algorithmHS = Algorithm.HMAC256("secret");
-------------------------------------------------------------------------
//RSA

Map<String,Object> keys=RSAUtils.getKeys();
RSAPublicKey publicKey = (RSAPublicKey)keys.get("public"); //Get the key instanceRSAPrivateKey privateKey = (RSAPrivateKey)keys.get("private");//Get the key instance
Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);

2 , 生成token

用HS256生成token

try {Algorithm algorithm = Algorithm.HMAC256("secret");String token = JWT.create().withIssuer("auth0").sign(algorithm);
} catch (UnsupportedEncodingException exception){//UTF-8 encoding not supported
} catch (JWTCreationException exception){//Invalid Signing configuration / Couldn't convert Claims.
}

用RS256生成token

 Map<String,Object> keys=RSAUtils.getKeys();RSAPublicKey publicKey = (RSAPublicKey)keys.get("public"); //Get the key instanceRSAPrivateKey privateKey = (RSAPrivateKey)keys.get("private");//Get the key instance
try {Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);String token = JWT.create().withIssuer("auth0").sign(algorithm);
} catch (JWTCreationException exception){//Invalid Signing configuration / Couldn't convert Claims.
}

3, 验证token

1)普通验证

用HS256验证token

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
try {Algorithm algorithm = Algorithm.HMAC256("secret");JWTVerifier verifier = JWT.require(algorithm).withIssuer("auth0").build(); //Reusable verifier instanceDecodedJWT jwt = verifier.verify(token);
} catch (UnsupportedEncodingException exception){//UTF-8 encoding not supported
} catch (JWTVerificationException exception){//Invalid signature/claims
}

用RS256验证token

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);JWTVerifier verifier = JWT.require(algorithm).withIssuer("auth0").build(); //Reusable verifier instanceDecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){//Invalid signature/claims
}

2)在payLoad 是可以自定义数据,用于验证,包括时间等。

在生成token的时候指定数据:

@Testpublic void gen1() throws IOException {String token ="";SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//日期转字符串Calendar calendar = Calendar.getInstance();calendar.add(Calendar.SECOND,30 ); //特定时间的年后Date date = calendar.getTime();try {Algorithm algorithm = Algorithm.HMAC256("mysecrite");token = JWT.create().withIssuer("auth0").withSubject("xiaoming").withClaim("name", 123).withArrayClaim("array", new Integer[]{1, 2, 3}).withExpiresAt(date).sign(algorithm);System.out.println("loglogagel:"+token);} catch (UnsupportedEncodingException exception){//UTF-8 encoding not supported} catch (JWTCreationException exception){//Invalid Signing configuration / Couldn't convert Claims.
       }}

验证token是否过期,是否有制定的

@Testpublic void gen3(){String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoMCIsImV4cCI6MTQ5NzY4NTQwOX0.DHY-90JAA63_TvI-gRZ2oHCIItMajb45zB1tdCHQ_NQ";try {Algorithm algorithm = Algorithm.HMAC256("mysecrite");JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(algorithm).withIssuer("auth0").withSubject("xiaomong");Clock clock = new Clock() {@Overridepublic Date getToday() {return new Date();}};//Must implement Clock interfaceJWTVerifier verifier = verification.build(clock);DecodedJWT jwt = verifier.verify(token);System.out.println(jwt.getAlgorithm());System.out.println(jwt.getType());System.out.println(jwt.getIssuer());System.out.println(jwt.getExpiresAt());} catch (UnsupportedEncodingException exception){//UTF-8 encoding not supported
          exception.printStackTrace();} catch (JWTVerificationException exception){//Invalid signature/claims
          exception.printStackTrace();}
}

如果 subject验证的不一致,就会报如下错误:

如果时间超过 30 秒,会报如下错误:

对验证的方法稍加修改:

 @Testpublic void gen3(){String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4aWFvbWluZyIsImFycmF5IjpbMSwyLDNdLCJpc3MiOiJhdXRoMCIsIm5hbWUiOiJJYW0gcmlnaHQgZnJvbSBjbGFpbSIsImV4cCI6MTQ5NzY4OTQ4NX0.6lsXISVAgi8B2wAvaZq4tj-h9Pgd6GGaOYZLz_gPFMU";try {Algorithm algorithm = Algorithm.HMAC256("mysecrite");JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(algorithm).withIssuer("auth0").withSubject("xiaoming");Clock clock = new Clock() {@Overridepublic Date getToday() {return new Date();}};//Must implement Clock interfaceJWTVerifier verifier = verification.build(clock);DecodedJWT jwt = verifier.verify(token);Map<String, Claim> claims = jwt.getClaims();    //Key is the Claim nameClaim claim = claims.get("name");System.out.println(claim.asString());    //打印出claim的值
          System.out.println(jwt.getAlgorithm());System.out.println(jwt.getType());System.out.println(jwt.getIssuer());System.out.println(jwt.getExpiresAt());} catch (UnsupportedEncodingException exception){//UTF-8 encoding not supported
          exception.printStackTrace();} catch (JWTVerificationException exception){//Invalid signature/claims
          exception.printStackTrace();}

验证后的最后结果:

4,claim的添加,获取

1) 内置的payload主要有以下几个,如果没有就返回null

Issuer ("iss") :发布者

String issuer = jwt.getIssuer();

Subject ("sub")

String subject = jwt.getSubject();

Audience ("aud")

List<String> audience = jwt.getAudience();

Expiration Time ("exp")

Date expiresAt = jwt.getExpiresAt();

Not Before ("nbf")

Date notBefore = jwt.getNotBefore();

Issued At ("iat")

Date issuedAt = jwt.getIssuedAt();

JWT ID ("jti")

String id = jwt.getId();

2)定义私有的claim

添加:

String token = JWT.create().withClaim("name", 123).withArrayClaim("array", new Integer[]{1, 2, 3}).sign(algorithm);

获取:

JWTVerifier verifier = JWT.require(algorithm).withClaim("name", 123).withArrayClaim("array", 1, 2, 3).build();
DecodedJWT jwt = verifier.verify("my.jwt.token");

目前,官方支持claim的类型的有:Boolean, Integer, Double, String, Date , String[] 和 Integer.

5,  Header Claims

1)header claims 是定义header部分的内容,基本都是默认定义,不需要自己去设置的,内置的有:

Algorithm ("alg")

String algorithm = jwt.getAlgorithm();

Type ("typ")

String type = jwt.getType();

Content Type ("cty")

String contentType = jwt.getContentType();

Key Id ("kid")

String keyId = jwt.getKeyId();

2)添加:

Map<String, Object> headerClaims = new HashMap();
headerClaims.put("owner", "auth0");
String token = JWT.create().withHeader(headerClaims).sign(algorithm);

3)获取:

Claim claim = jwt.getHeaderClaim("owner");

总结: 看了其他人的一些博客,发现他们的api都是相对老一点的版本,生成token是一步一步来,新的确实简单方便很多。分享就这里,欢迎交流。

补充参考链接:

web 中使用jwt:    https://github.com/jwtk/jjwt

参考地址:https://github.com/auth0/java-jwt

转载于:https://www.cnblogs.com/minsons/p/7040753.html

JSON Web Tokens(JWT)相关推荐

  1. JSON WEB TOKEN(JWT)的分析

    JSON WEB TOKEN(JWT)的分析 一般情况下,客户的会话数据会存在文件中,或者引入redis来存储,实现session的管理,但是这样操作会存在一些问题,使用文件来存储的时候,在多台机器上 ...

  2. 10分钟了解JSON Web令牌(JWT)

    JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.虫虫今天给大家介绍JWT的原理和用法. 1.跨域身份验证 Internet服务无法与用户身份验证分开.一般过程如下. 1.用户 ...

  3. Json Web Token(JWT)

    JsonWebToken 概述 如果各位不了解 JWT,不要紧张,它并不可怕. JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信 ...

  4. 后端架构token授权认证机制:spring security JSON Web Token(JWT)简例

    后端架构token授权认证机制:spring security JSON Web Token(JWT)简例 在基于token的客户端-服务器端认证授权以前,前端到服务器端的认证-授权通常是基于sess ...

  5. php后台跨域token,JSON Web Token(JWT)目前最流行的跨域身份验证解决方案(PHP)类...

    JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,下面我自己封装了一个PHP的Jwt类,直接复制即可使用,无需composer安装包: 常规的身份验证流程为: 该方案的最大的短 ...

  6. jwt 私钥_什么是 JSON Web Token(JWT)

    有关本文档的快速链接,请参考页面提示. 什么是 JSON Web Token(JWT)? JSON Web Token (JWT) 作为一个开放的标准 (RFC 7519) 定义了一种简洁自包含的方法 ...

  7. 单点登录SSO----JSON Web Token(JWT)机制

    JSON Web Token(JWT)机制 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns: ...

  8. jwt令牌_jwt-cli:用于解码JSON Web令牌(JWT令牌)的Shell库

    jwt令牌 当我开始经常需要解码JSON Web令牌时,我感到迫切需要编写允许我快速进行操作的程序. 有很多不错的选项,例如jwt.io ,但是一旦您需要执行此操作,它通常就会变得笨拙. 并且,如果您 ...

  9. jwt-cli:一个用于解码JSON Web令牌(JWT令牌)的Shell库

    当我开始经常需要解码JSON Web令牌时,我感到迫切需要编写允许我快速进行操作的程序. 有很多不错的选项,例如jwt.io ,但是一旦您需要执行此操作,它通常就会变得笨拙. 而且,如果您需要处理多个 ...

最新文章

  1. 90.前端 :执行方法前提示功能
  2. 用python画猫咪怎么画-如何用Python实现可视化地图
  3. 学生用的笔记本电脑什么样的好_大学生用的学生党笔记本什么牌子好,听听学姐的...
  4. zeekooper集群搭建_Zookeeper与Kafka集群搭建完整教程
  5. [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望
  6. java基础—多线程下的单例设计模式的安全问题
  7. linux nginx jsp,将nginx注册成linux的服务(service)
  8. 只会java_只会码代码的你和Java工程师之间的差距有大?
  9. Android【报错】android.content.ActivityNotFoundException:activity in yourAndroidManifest.?
  10. Gstreamer官方教程汇总2---GStreamer concepts
  11. Objective-C与Swift下的自定义打印函数(Debug和Release)
  12. linux下usb无线网卡对比
  13. 腾达U12无线网卡驱动安装教程
  14. 梅科尔工作室-PR第三次培训笔记(效果与转场及插件使用)
  15. 教育行业 服务器虚拟化,教育行业桌面虚拟化方案
  16. workman定时任务队列雏形
  17. 软件设计师2022记录
  18. objective-c类别catagory的作用?
  19. MarkDown Pad2的Windows秘钥
  20. Macbook Pro(无法完全)通过序列号与激活时间辨别是否为翻新机

热门文章

  1. hql懒加载后判断对象是否存在_hibernate延迟加载(懒加载)详解
  2. 养蛙游戏刷爆朋友圈,养蛙成功“反杀”传统手游?
  3. 萌新资源 | 3D基础——渲染基本原理介绍
  4. 论文格式——合适【CSDN】发文
  5. php socket(服务端与客户端)demo
  6. 关乎每个人!2021年5月1日起实施
  7. 网络安全第一讲 计算机网络安全概述
  8. 【水滴石穿】imooc_gp
  9. MySQL升级后 MySQL 5.7 时间不兼容问题
  10. GitHub 上 57 款最流行的开源深度学习项目【转】