"常见的身份验证方式有哪些?" 常用认证机制有哪些( 二 )

  • 占带宽,正常情况下要比 session_id 更大,需要消耗更多流量 , 挤占更多带宽,假如你的网站每月有 10 万次的浏览器,就意味着要多开销几十兆的流量 。听起来并不多,但日积月累也是不小一笔开销 。实际上,许多人会在 JWT 中存储的信息会更多
  • 无法在服务端注销 , 因为服务端是无状态的,并没有保存客户端用户登录信息
  • 对于有着严格性能要求的 Web 应用并不理想,尤其对于单线程环境
5. JWT5.1. JWT介绍
JWT全称为JSON Web Token,是目前最流行的跨域身份验证解决方案 。JWT是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准 。
JWT特别
"常见的身份验证方式有哪些?",常用认证机制有哪些 。小编来告诉你更多相关信息 。
常用认证机制有哪些 适用于分布式站点的单点登录(SSO)场景 。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息 , 以便于从资源服务器获取资源,也可被加密 。
5.2. JWT的数据结构
JWT其实就是一个很长的字符串 , 字符之间通过”.”分隔符分为三个子串,各字串之间没有换行符 。每一个子串表示了一个功能块,总共有三个部分:JWT头(header)、有效载荷(payload)、签名(signature)
如下图所示:
"常见的身份验证方式有哪些?" 常用认证机制有哪些

文章插图
5.2.1. JWT头JWT头是一个描述JWT元数据的JSON对象,通常如下所示:
{\"alg\": \"HS256\",\"typ\": \"JWT\"}alg:表示签名使用的算法,默认为HMAC SHA256(写为HS256)
typ:表示令牌的类型,JWT令牌统一写为JWT
最后 , 使用Base64 URL算法将上述JSON对象转换为字符串
5.2.2. 有效载荷
有效载荷,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据 。
有效载荷部分规定有如下七个默认字段供选择:
iss:发行人exp:到期时间sub:主题aud:用户nbf:在此之前不可用iat:发布时间jti:JWT ID用于标识该JWT除以上默认字段外,还可以自定义私有字段
最后,同样使用Base64 URL算法将有效载荷部分JSON对象转换为字符串
5.2.3. 签名
签名实际上是一个加密的过程 , 是对上面两部分数据通过指定的算法生成哈希,以确保数据不会被篡改 。
首先需要指定一个密码(secret),该密码仅仅保存在服务器中,并且不能向用户公开 。然后使用JWT头中指定的签名算法(默认情况下为HMAC SHA256) , 根据以下公式生成签名哈希:
HMACSHA256(base64UrlEncode(header) + \".\" + base64UrlEncode(payload),secret)在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用”.”分隔,就构成整个JWT对象
5.3. JWT签名算法JWT签名算法中,一般有两个选择:
  • HS256:HS256 (带有 SHA-256 的 HMAC )是一种对称加密算法, 双方之间仅共享一个密钥 。由于使用相同的密钥生成签名和验证签名, 因此必须注意确保密钥不被泄密
  • RS256:RS256 (采用SHA-256 的 RSA 签名) 是一种非对称加密算法, 它使用公共/私钥对: JWT的提供方采用私钥生成签名, JWT 的使用方获取公钥以验证签名"常见的身份验证方式有哪些?",常用认证机制有哪些 。小编来告诉你更多相关信息 。
    常用认证机制有哪些
6. jwt入门案例
jjwt是一个提供JWT创建和验证的Java库 。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解 。
jjwt的maven坐标:
io.jsonwebtokenjjwt0.9.16.1. jwt入门案例本案例中会通过jjwt来生成和解析JWT令牌 。
【步骤一】:创建maven工程jwt_demo并配置pom.xml文件4.0.0com.zbbmetajwt_demo1.0-SNAPSHOTio.jsonwebtokenjjwt0.9.1junitjunit4.12cn.hutoolhutool-all5.1.0【步骤二】:编写单元测试package com.zbbmeta.test;import cn.hutool.core.io.FileUtil;import io.jsonwebtoken.*;import org.junit.Test;import java.io.DataInputStream;import java.io.InputStream;import java.security.*;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;public class JwtTest {//生成jwt,不使用签名@Testpublic void test1(){//添加构成JWT的参数Map headMap = new HashMap();headMap.put(\"alg\", \"none\");//不使用签名算法headMap.put(\"typ\", \"JWT\");Map body = new HashMap();body.put(\"userId\",\"1\");body.put(\"username\",\"xiaoming\");body.put(\"role\",\"admin\");String jwt = Jwts.builder().setHeader(headMap).setClaims(body).setId(\"jwt001\").compact();System.out.println(jwt);//解析jwtJwt result = Jwts.parser().parse(jwt);Object jwtBody = result.getBody();Header header = result.getHeader();System.out.println(result);System.out.println(jwtBody);System.out.println(header);}//生成jwt时使用签名算法生成签名部分----基于HS256签名算法@Testpublic void test2(){//添加构成JWT的参数Map headMap = new HashMap();headMap.put(\"alg\", SignatureAlgorithm.HS256.getValue());//使用HS256签名算法headMap.put(\"typ\", \"JWT\");Map body = new HashMap();body.put(\"userId\",\"1\");body.put(\"username\",\"xiaoming\");body.put(\"role\",\"admin\");String jwt = Jwts.builder().setHeader(headMap).setClaims(body).setId(\"jwt001\").signWith(SignatureAlgorithm.HS256,\"zbbmeta\").compact();System.out.println(jwt);//解析jwtJwt result = Jwts.parser().setSigningKey(\"zbbmeta\").parse(jwt);Object jwtBody = result.getBody();Header header = result.getHeader();System.out.println(result);System.out.println(jwtBody);System.out.println(header);}//生成自己的 秘钥/公钥 对@Testpublic void test4() throws Exception{//自定义 随机密码,请修改这里String password = \"zbbmeta\";KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");SecureRandom secureRandom = new SecureRandom(password.getBytes());keyPairGenerator.initialize(1024, secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();byte[] publicKeyBytes = keyPair.getPublic().getEncoded();byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();FileUtil.writeBytes(publicKeyBytes, \"d:\\\\pub.key\");FileUtil.writeBytes(privateKeyBytes, \"d:\\\\pri.key\");}//生成jwt时使用签名算法生成签名部分----基于RS256签名算法@Testpublic void test3() throws Exception{//添加构成JWT的参数Map headMap = new HashMap();headMap.put(\"alg\", SignatureAlgorithm.RS256.getValue());//使用RS256签名算法headMap.put(\"typ\", \"JWT\");Map body = new HashMap();body.put(\"userId\",\"1\");body.put(\"username\",\"xiaoming\");body.put(\"role\",\"admin\");String jwt = Jwts.builder().setHeader(headMap).setClaims(body).setId(\"jwt001\").signWith(SignatureAlgorithm.RS256,getPriKey()).compact();System.out.println(jwt);//解析jwtJwt result = Jwts.parser().setSigningKey(getPubKey()).parse(jwt);Object jwtBody = result.getBody();Header header = result.getHeader();System.out.println(result);System.out.println(jwtBody);System.out.println(header);}//获取私钥public PrivateKey getPriKey() throws Exception{InputStream resourceAsStream =this.getClass().getClassLoader().getResourceAsStream(\"pri.key\");DataInputStream dis = new DataInputStream(resourceAsStream);byte[] keyBytes = new byte[resourceAsStream.available()];dis.readFully(keyBytes);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory kf = KeyFactory.getInstance(\"RSA\");return kf.generatePrivate(spec);}//获取公钥public PublicKey getPubKey() throws Exception{InputStream resourceAsStream =this.getClass().getClassLoader().getResourceAsStream(\"pub.key\");DataInputStream dis = new DataInputStream(resourceAsStream);byte[] keyBytes = new byte[resourceAsStream.available()];dis.readFully(keyBytes);X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);KeyFactory kf = KeyFactory.getInstance(\"RSA\");return kf.generatePublic(spec);}}