重庆网站建设价格,平台做网站点击,北京网站优化体验,怎么在网站添加链接jwt简介
以下介绍来自官网#xff08;https://jwt.io/#xff09; SON Web 令牌 #xff08;JWT#xff09; 是一种开放标准 #xff08;RFC 7519#xff09;#xff0c;它定义了一种紧凑且独立的方式#xff0c;用于在各方之间以 JSON 对象的形式安全地传输信息。此信…jwt简介
以下介绍来自官网https://jwt.io/ SON Web 令牌 JWT 是一种开放标准 RFC 7519它定义了一种紧凑且独立的方式用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任因为它是经过数字签名的。JWT 可以使用密钥使用 HMAC 算法或使用 RSA 或 ECDSA 的公钥/私钥对进行签名**来自官网**。
尽管 JWT 可以加密以提供各方之间的保密性但我们将专注于签名令牌。签名令牌可以验证其中包含的声明的完整性而加密令牌则向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时签名还证明只有持有私钥的一方才是签名的一方**来自官网**。
使用场景 授权这是使用 JWT 的最常见方案。用户登录后每个后续请求都将包含 JWT允许用户访问使用该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能因为它的开销很小并且能够跨不同域轻松使用**来自官网**。 信息交换JSON Web 令牌是在各方之间安全传输信息的好方法。由于 JWT 可以签名例如使用公钥/私钥对因此您可以确定发件人是他们所说的人。此外由于签名是使用标头和有效负载计算的因此您还可以验证内容是否未被篡改**来自官网**。
jwt的组成结构
HeaderPayloadSignature 因此JWT 通常如下所示。
xxxxx.yyyyy.zzzzzHeader
通常由两部分组成令牌的类型即 JWT和正在使用的签名算法例如 HMAC SHA256 或 RSA。 例如
{alg: HS256,typ: JWT
}然后此JSON被Base64Url编码以形成JWT的第一部
Payload有效载荷
令牌的第二部分是有效负载其中包含声明。声明是有关实体通常是用户和其他数据的语句。 有三种类型的声明已注册、公共和私人声明。 已注册声明这些是一组预定义的声明这些声明不是必需的但建议使用以提供一组有用的、可互操作的声明。其中一些是iss发行人exp到期时间sub主题aud受众等。
请注意声明名称只有三个字符长因为 JWT 应该是紧凑的。
公共声明这些可以由使用 JWT 的人随意定义。但为了避免冲突它们应该在 IANA JSON Web 令牌注册表中定义或者定义为包含抗冲突命名空间的 URI。
专用声明这些是创建的自定义声明用于在同意使用它们的各方之间共享信息既不是注册声明也不是公共声明。
示例有效负载可以是
{sub: 1234567890,name: John Doe,admin: true
}sub是预定义的声明name,admin则是自己随便添加的一些定义 然后对有效负载进行 Base64Url 编码以形成 JSON Web 令牌的第二部分。
请注意对于签名令牌此信息虽然受到篡改保护但任何人都可以读取。不要将机密信息放在 JWT 的有效负载或标头元素中除非它已加密。
签名
要创建签名部分您必须获取编码的标头、编码的有效负载、机密、标头中指定的算法并对其进行签名。
例如如果要使用 HMAC SHA256 算法将按以下方式创建签名
HMACSHA256(base64UrlEncode(header) . base64UrlEncode(payload),secret)签名用于验证消息在此过程中未被更改并且在使用私钥签名的令牌的情况下它还可以验证 JWT 的发件人是否是它所说的人。
把所有东西放在一起 输出是三个由点分隔的 Base64-URL 字符串可以在 HTML 和 HTTP 环境中轻松传递同时与基于 XML 的标准如 SAML相比更加紧凑。
使用java-jwt来生成和解析token
导入maven依赖
dependencygroupIdcom.auth0/groupIdartifactIdjava-jwt/artifactIdversion3.4.0/version/dependency这附上一段我之前写的代码 public String getToken(Users user) {String token;// 2*24*3600 * 1000token JWT.create().withExpiresAt(new Date(System.currentTimeMillis() (2*24*3600*1000))).withAudience(user.getEmployeeId())// 将 login_user 保存到 token 里面.sign(Algorithm.HMAC256(DigestUtils.md5Hex(user.getEmployeePassword() Constants.MD5PRIVATEKEY)));// 以 password 作为 token 的密钥return token;}这是上面引入的依赖提供的方法 首先是 JWT.create()create方法去调用了JWTCreator的init方法
public static JWTCreator.Builder create() {return JWTCreator.init();}然后init方法又new了一个自己的内部类内部类给头部(headerClaims)和载荷(payloadClaims)声明了引用地址 /*** Initialize a JWTCreator instance.** return a JWTCreator.Builder instance to configure.*/static JWTCreator.Builder init() {return new Builder();}/*** The Builder class holds the Claims that defines the JWT to be created.*/public static class Builder {private final MapString, Object payloadClaims;private MapString, Object headerClaims;Builder() {this.payloadClaims new HashMap();this.headerClaims new HashMap();}紧接着withExpiresAt()和withAudience()实际上就是给载荷里预定义的声明赋值withExpiresAt()就是给exp赋值,withAudience()就是给aud赋值 /*** Add a specific Audience (aud) claim to the Payload.** param audience the Audience value.* return this same Builder instance.*/public Builder withAudience(String... audience) {addClaim(PublicClaims.AUDIENCE, audience);return this;}/*** Add a specific Expires At (exp) claim to the Payload.** param expiresAt the Expires At value.* return this same Builder instance.*/public Builder withExpiresAt(Date expiresAt) {addClaim(PublicClaims.EXPIRES_AT, expiresAt);return this;}它们都调用了addClaim方法可以看到就是在载荷的那个map中添加key和value private void addClaim(String name, Object value) {if (value null) {payloadClaims.remove(name);return;}payloadClaims.put(name, value);}前面说过也可以自定义声明添加到载荷这部分这里也提供了多个方法这里展示两个 /*** Add a custom Claim value.** param name the Claims name.* param value the Claims value.* return this same Builder instance.* throws IllegalArgumentException if the name is null.*/public Builder withClaim(String name, Boolean value) throws IllegalArgumentException {assertNonNull(name);addClaim(name, value);return this;}/*** Add a custom Claim value.** param name the Claims name.* param value the Claims value.* return this same Builder instance.* throws IllegalArgumentException if the name is null.*/public Builder withClaim(String name, Integer value) throws IllegalArgumentException {assertNonNull(name);addClaim(name, value);return this;}然后是sign()方法这里这里传入了一个我们指明秘钥的算法headerClaims.put方法给头部添加了令牌的类型即 JWT和正在使用的签名算法
/*** Creates a new JWT and signs is with the given algorithm** param algorithm used to sign the JWT* return a new JWT token* throws IllegalArgumentException if the provided algorithm is null.* throws JWTCreationException if the claims could not be converted to a valid JSON or there was a problem with the signing key.*/public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {if (algorithm null) {throw new IllegalArgumentException(The Algorithm cannot be null.);}headerClaims.put(PublicClaims.ALGORITHM, algorithm.getName());headerClaims.put(PublicClaims.TYPE, JWT);String signingKeyId algorithm.getSigningKeyId();if (signingKeyId ! null) {withKeyId(signingKeyId);}return new JWTCreator(algorithm, headerClaims, payloadClaims).sign();}然后new 了一个JWTCreator对象 private JWTCreator(Algorithm algorithm, MapString, Object headerClaims, MapString, Object payloadClaims) throws JWTCreationException {this.algorithm algorithm;try {ObjectMapper mapper new ObjectMapper();SimpleModule module new SimpleModule();module.addSerializer(ClaimsHolder.class, new PayloadSerializer());mapper.registerModule(module);mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);headerJson mapper.writeValueAsString(headerClaims);payloadJson mapper.writeValueAsString(new ClaimsHolder(payloadClaims));} catch (JsonProcessingException e) {throw new JWTCreationException(Some of the Claims couldnt be converted to a valid JSON format., e);}}这里可以看到这两句代码把头部这个map和载荷这个map都转换成了json串 headerJson mapper.writeValueAsString(headerClaims);payloadJson mapper.writeValueAsString(new ClaimsHolder(payloadClaims));然后返回在new一个JWTCreator对象后又调用了这个对象的sign()方法 private String sign() throws SignatureGenerationException {String header Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));String payload Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));String content String.format(%s.%s, header, payload);byte[] signatureBytes algorithm.sign(content.getBytes(StandardCharsets.UTF_8));String signature Base64.encodeBase64URLSafeString((signatureBytes));return String.format(%s.%s, content, signature);}可以看到首先对header也就是头部做了base64编码,然后对载荷 payload也做了base64编码
String header Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));
String payload Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));然后使用小数点连接
String content String.format(%s.%s, header, payload);然后使用算法对连接后的头部和载荷进行签名最后形成签名
byte[] signatureBytes algorithm.sign(content.getBytes(StandardCharsets.UTF_8));然后用base64对签名进行编码再把编码后的签名和前面的头部载荷连接起来
String signature Base64.encodeBase64URLSafeString((signatureBytes));return String.format(%s.%s, content, signature);