我司网站改版上线网站建设,wordpress后台排版错乱,中国工程建设焊接协会网站,注册微信公众平台JWT#xff08;JSON Web Token#xff09;是一种开放标准#xff08;RFC 7519#xff09;#xff0c;它定义了一种紧凑且自包含的方式#xff0c;用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的#xff0c;因为它可以使用JSON对象在各方…JWTJSON Web Token是一种开放标准RFC 7519它定义了一种紧凑且自包含的方式用于在各方之间以JSON对象的形式安全地传输信息。JWT通常用于身份验证和授权目的因为它可以使用JSON对象在各方之间安全地传输信息
官网地址https://jwt.io/
0.介绍
通俗地说JWT的本质就是一个字符串它是将用户信息保存到一个Json字符串中然后进行编码后得到一个JWT token并且这个JWT token带有签名信息接收后可以校验是否被篡改所以可以用于在各方之间安全地将信息作为Json对象传输。
0.1.JWT的应用场景
身份验证 : 当用户成功登录时服务器会生成一个JWT并将其发送给客户端。客户端在后续请求中将JWT附加到HTTP请求头中以此来证明用户的身份。
授权 : JWT中可以包含用户的权限信息这样服务器可以根据这些信息决定用户是否被允许访问某些资源。
信息传递 : 除了用户的身份和权限外JWT还可以用来携带其他有用的信息如用户的偏好设置等。
在 java 中 常与 Spring Security 框架配合使用
JWT的认证流程如下
首先前端通过Web表单将自己的用户名和密码发送到后端的接口这个过程一般是一个POST请求。建议的方式是通过SSL加密的传输(HTTPS)从而避免敏感信息被嗅探后端核对用户名和密码成功后将包含用户信息的数据作为JWT的Payload将其与JWT Header分别进行Base64编码拼接后签名形成一个JWT Token形成的JWT Token就是一个如同lll.zzz.xxx的字符串后端将JWT Token字符串作为登录成功的结果返回给前端。前端可以将返回的结果保存在浏览器中退出登录时删除保存的JWT Token即可前端在每次请求时将JWT Token放入HTTP请求头中的Authorization属性中(解决XSS和XSRF问题)后端检查前端传过来的JWT Token验证其有效性比如检查签名是否正确、是否过期、token的接收方是否是自己等等验证通过后后端解析出JWT Token中包含的用户信息进行其他逻辑操作(一般是根据用户信息得到权限等)返回结果 0.2.优点
这种基于token的认证方式相比传统的session认证方式更节约服务器资源并且对移动端和分布式更加友好。其优点如下 支持跨域访问cookie是无法跨域的而token由于没有用到cookie(前提是将token放到请求头中)所以跨域后不会存在信息丢失问题 无状态token机制在服务端不需要存储session信息因为token自身包含了所有登录用户的信息所以可以减轻服务端压力 更适用CDN可以通过内容分发网络请求服务端的所有资料 更适用于移动端当客户端是非浏览器平台时cookie是不被支持的此时采用token认证方式会简单很多 无需考虑CSRF由于不再依赖cookie所以采用token认证方式不会发生CSRF所以也就无需考虑CSRF的防御
1.JWT的结构
JWT是一种自包含的令牌格式。JWT由三个部分组成头部、载荷和签名。 1.1.头部 (Header)
头部通常包含两个部分
typ: 表示该令牌的类型通常是“JWT”。alg: 指定签名算法例如 HMAC SHA-256 或 RSA。
头部通常以JSON格式书写并经过Base64Url编码。
1.2.载荷 (Payload)
载荷包含了需要作为声明传输的信息。这些声明可以分为三类
标准声明由JWT规范定义的声明。 iss (issuer): 发行者。sub (subject): 主题通常是指用户ID。aud (audience): 接收者即令牌的预期受众。exp (expiration time): 过期时间。nbf (not before): 该时间之前不可使用。iat (issued at): 发行时间。jti (JWT ID): 一个唯一的标识符用于防止重放攻击。 私有声明由发行者和接收者约定的声明例如用户的角色或权限等。公共声明虽然不是JWT规范的一部分但可以在任何JWT中使用。
载荷也是经过Base64Url编码的。
1.3.签名 (Signature)
签名部分保证了JWT的完整性和安全性。签名通过将头部和载荷进行编码并使用指定的算法如HMAC SHA-256 RSA或ECDSA进行计算得到。签名确保了
令牌没有被篡改。令牌是由可信的一方发行的。
签名部分同样经过Base64Url编码。
1.4.JWS, JWK
JWS 也就是JWT Signature其结构就是在之前nonsecure JWT的基础上在头部声明签名算法并在最后添加上签名。创建签名是保证jwt不能被他人随意篡改。我们通常使用的JWT一般都是JWS
为了完成签名除了用到header信息和payload信息外还需要算法的密钥也就是secretKey。
加密的算法一般有2类
对称加密secretKey指加密密钥可以生成签名与验签非对称加密secretKey指私钥只用来生成签名不能用来验签(验签用的是公钥)
JWT的密钥或者密钥对一般统一称为JSON Web Key也就是JWK
到目前为止jwt的签名算法有三种
HMAC【哈希消息验证码(对称)】HS256/HS384/HS512RSASSA【RSA签名算法(非对称)】 :RS256/RS384/RS512ECDSA【椭圆曲线数据签名算法(非对称)】 :ES256/ES384/ES512
2.实现与工具
2.1.jjwt (Java JWT)
GitHub 仓库地址https://github.com/jwtk/jjwt
这是一个基于Java的库用于在JVM和Android平台上创建和验证JSON Web Tokens (JWTs)和JSON Web Keys (JWKs)。
它支持多种JOSE工作组的RFC规范:
RFC 7519: JSON Web Token (JWT)RFC 7515: JSON Web Signature (JWS)RFC 7516: JSON Web Encryption (JWE)等等
2.1.1.导入Maven依赖
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-api/artifactIdversion0.11.5/version
/dependency
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-impl/artifactIdversion0.11.5/version
/dependency
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-jackson/artifactIdversion0.11.5/version
/dependency2.1.2.测试代码
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.security.Key;
import java.util.Date;
import java.util.UUID;RestController
public class JwtController {// 密钥 : 实际开发时 应该从 配置文件 / 持久化存储中 获取private String secret;// token时效24小时public static final long EXPIRE 1000 * 60 * 60 * 24;RequestMapping(/create)public String createToken(){// 生成一个随机的密钥 IDString keyId UUID.randomUUID().toString();// 密钥secret keyId;// 创建一个 JWT 令牌String jwt Jwts.builder()// 设置JWT头部参数指定令牌类型为JWT.setHeaderParam(typ, JWT)// 设置JWT头部参数指定签名算法为HS256.setHeaderParam(alg, HS256)// 设置JWT过期时间当前时间戳加上设定的过期时长.setExpiration(new Date(System.currentTimeMillis() EXPIRE))// 设置主题通常是用户身份标识.setSubject(admin)// 添加角色声明.claim(role, admin)// 设置用户ID为1.claim(id, 1)// 设置用户昵称为王小二.claim(nickname, 王小二)// 设置令牌签发时间.setIssuedAt(new Date())// 设置唯一标识符.setId( keyId )// 使用HS256算法和密钥签名.signWith(SignatureAlgorithm.HS256, secret.getBytes())// 将令牌压缩为紧凑形式的字符串.compact();return jwt;}RequestMapping(/check)public void checkToken(String jwt) {System.out.println(jwt jwt);// 创建一个安全的密钥Key secureKey Keys.hmacShaKeyFor(secret.getBytes());try {// 使用Jwts.parserBuilder()方法构建一个解析器该解析器使用secureKey作为签名密钥// 然后使用这个解析器解析jwt字符串获取到Claims对象即JWT的主体部分Claims claims Jwts.parserBuilder().setSigningKey(secureKey).build().parseClaimsJws(jwt).getBody();// 打印解析后的 JWT 信息System.out.println(Subject: claims.getSubject());System.out.println(Role: claims.get(role, String.class));System.out.println(Issue Time: claims.getIssuedAt());System.out.println(JWT ID: claims.getId());System.out.println(user nickname: claims.get(nickname));// 可以在这里添加更多逻辑来验证 JWT 的有效性例如检查过期时间等if(claims.getExpiration()null){System.out.println(过期时间不能为空 Expiration time cannot be null);}} catch (Exception e) {// 如果 JWT 无法验证这里会捕获异常System.err.println(Invalid JWT: e.getMessage());}}
}
2.2.Nimbus
Nimbus JOSE JWT 是一个非常强大的 Java 库用于处理 JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), JSON Web Token (JWT) 和 OAuth 2.0 授权服务器。这个库是由 NimbusDS 开发的并且广泛应用于身份验证和授权系统中。
2.2.1.导入依赖
首先您需要在 Maven 项目中添加 json-jwt 的依赖 dependencygroupIdcom.nimbusds/groupIdartifactIdnimbus-jose-jwt/artifactIdversion9.40/version/dependency2.2.2.测试代码 import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.text.ParseException;
import java.util.Date;
import java.util.UUID;RestController
public class JwtController {// 密钥 : 实际开发时 应该从 配置文件 / 持久化存储中 获取private String secret;RequestMapping(/create)public String createToken() {try {// 生成一个随机的密钥 IDString keyId UUID.randomUUID().toString();// 密钥secret keyId;// 创建一个 HMAC 签名器MACSigner signer new MACSigner(secret.getBytes());// 设置 JWT 的声明JWTClaimsSet.Builder builder new JWTClaimsSet.Builder();builder.subject(admin);builder.claim(role, admin);builder.issueTime(new Date());builder.jwtID(keyId);// 构建 JWT Claims SetJWTClaimsSet claimsSet builder.build();// 创建一个空的 SignedJWT 对象SignedJWT signedJWT new SignedJWT(new JWSHeader(JWSAlgorithm.HS256),claimsSet);// 签名 JWTsignedJWT.sign(signer);// 将 JWT 转换为紧凑形式String jwt signedJWT.serialize();return jwt;} catch (JOSEException e) {e.printStackTrace();}return null;}RequestMapping(/check)public void checkToken(String jwt) {try {System.out.println(jwt jwt);// 解析 JWTSignedJWT signedJWT SignedJWT.parse(jwt);// 验证 JWTMACVerifier verifier new MACVerifier( secret.getBytes() );boolean isValid signedJWT.verify(verifier);if (!isValid) {System.out.println(无效的 JWT 签名 Invalid JWT signature.);return;}// 获取 JWT ClaimsJWTClaimsSet claimsSet signedJWT.getJWTClaimsSet();System.out.println(Subject: claimsSet.getSubject());System.out.println(Role: claimsSet.getStringClaim(role));System.out.println(Issue Time: claimsSet.getIssueTime());System.out.println(JWT ID: claimsSet.getJWTID());} catch (JOSEException | ParseException e) {e.printStackTrace();}}/*** token 通过 header传递* 再通过 request 取出*/RequestMapping(/checkHeader)public void checkHeaderToken(HttpServletRequest request) {try {String jwt request.getHeader(Authorization);System.out.println(jwt header jwt);// 解析 JWTSignedJWT signedJWT SignedJWT.parse(jwt);// 验证 JWTMACVerifier verifier new MACVerifier( secret.getBytes() );boolean isValid signedJWT.verify(verifier);if (!isValid) {System.out.println(无效的 JWT 签名 Invalid JWT signature.);return;}// 获取 JWT ClaimsJWTClaimsSet claimsSet signedJWT.getJWTClaimsSet();System.out.println(Subject: claimsSet.getSubject());System.out.println(Role: claimsSet.getStringClaim(role));System.out.println(Issue Time: claimsSet.getIssueTime());System.out.println(JWT ID: claimsSet.getJWTID());} catch (JOSEException | ParseException e) {e.printStackTrace();}}
}
2.2.3.请求测试
###
GET http://localhost:8080/create生成token : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyMzQ1MDgyOCwiaWF0IjoxNzIzMzY0NDI4LCJqdGkiOiI5Yzc3N2YwZC03NDU5LTQ3MTUtYmVkNy1mNWViYzJiNmMwOTgifQ.Y_P7L4gehl0kJwxTnwUxX8Yy502qrCHQ0hkxod58ly8
###
GET http://localhost:8080/check?jwteyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyMzQ1MDgyOCwiaWF0IjoxNzIzMzY0NDI4LCJqdGkiOiI5Yzc3N2YwZC03NDU5LTQ3MTUtYmVkNy1mNWViYzJiNmMwOTgifQ.Y_P7L4gehl0kJwxTnwUxX8Yy502qrCHQ0hkxod58ly8
idea 控制台: Subject: admin Role: admin Issue Time: Sun Aug 11 16:20:28 CST 2024 JWT ID: 9c777f0d-7459-4715-bed7-f5ebc2b6c098
###
GET http://localhost:8080/checkHeader
Content-Type: application/json
Authorization: eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyMzQ1MDgyOCwiaWF0IjoxNzIzMzY0NDI4LCJqdGkiOiI5Yzc3N2YwZC03NDU5LTQ3MTUtYmVkNy1mNWViYzJiNmMwOTgifQ.Y_P7L4gehl0kJwxTnwUxX8Yy502qrCHQ0hkxod58ly8idea 控制台: Subject: admin Role: admin Issue Time: Sun Aug 11 16:20:28 CST 2024 JWT ID: 9c777f0d-7459-4715-bed7-f5ebc2b6c098