JWT
JWT是指JSON Web Token,一种用于在网络上安全传输信息的开放标准(RFC 7519),定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。JWT由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature)。通常被用来在用户和服务器之间传递身份信息,以及在不同的系统之间安全地传递声明。JWT通常被用于身份验证和信息交换,特别是在前后端分离的应用中。
JWT工作示意图:
- 用户登录后,服务端会将用户的识别信息进行加密生成一个有有效期的token返回给用户端。
- 用户端收到token后将其进行保存,并在以后的每一次请求时将该token带上发送给服务器。
- 服务器接收到用户的token后,进行验证用户的身份、权限、有效期等信息,验证通过即放行,验证不通过就拒绝服务。
JWT由三部分组成,分别是头部(header)、载荷(payload)和签名(signature)。
- 头部(header):包含了令牌的类型(即JWT)和所使用的签名算法(例如HMAC SHA256或RSA)。
- 载荷(payload):包含了要传递的信息,以及一些标准的声明和自定义的声明。标准的声明包括令牌的过期时间(exp)、发布时间(iat)等。自定义的声明可以根据需要添加。
- 签名(signature):使用头部指定的算法和密钥对头部和载荷进行签名,以确保令牌在传输过程中没有被篡改。
JWT的三部分使用点号(.)连接起来,形成一个完整的JWT令牌。例如:xxxxx.yyyyy.zzzzz
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJaSEFOR1hVTiIsImJvZHkiOnsidXNlclJvbGUiOiJhZG1pbiIsInVzZXJpZCI6IjAwMSJ9LCJleHAiOjE2NjI5NTIxNjIsImlhdCI6MTY2Mjk1MTU1NywianRpIjoiZGZhN2MyZjUtNGNjMC00OWFhLWFiMDUtYzZhY2M4M2YxMDViIn0.xOleM21i7-EI0oOq83Xm-nQVOufajHCupY2QjkpwreQ
JWT通常用于身份验证和授权,因为它们可以包含用户的信息,并且可以被验证和信任。通常用于API认证,因为可以在多个系统之间安全地传递信息,而无需使用cookie或session。
JWT使用
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.4.0</version> </dependency>
@Slf4j @RestController public class TokenController { @Autowired private TokenUtil tokenUtil; @PostMapping("/login") public String login(@RequestParam String username, @RequestParam String password){ if(!"admin".equals(username) || !"123".equals(password)){ log.info("账号或者密码错误!"); } // 模拟从数据库中获取的用户识别信息 String userId = "001"; String userRole = "admin"; Map<String,Object> dataMap = new HashMap<>(); dataMap.put("userId", userId); dataMap.put("userRole", userRole); // 将用户识别信息存储到token中 String token = tokenUtil.createToken(dataMap); log.info("生成的token为:{}", token); return token; } @PostMapping("/getUserInfo") public String getUserInfo(@RequestParam String token){ if(ObjectUtils.isEmpty(token)){ log.info("token不能为空!"); return "token不能为空!"; } log.info("收到的token为:{}", token); Map<String, Object> dataMap = tokenUtil.parseToken(token); String userRole = dataMap.get("userRole").toString(); if(!"admin".equals(userRole)){ log.info("非管理员角色,不允许访问!"); return "非管理员角色,不允许访问!"; } String userId = dataMap.get("userId").toString(); return "允许登录,用户为:" + userId; } }
@Component public class TokenUtil { private static final String DEFAULT_SECRET = "666"; private static final String DEFAULT_DATA_KEY = "body"; private static final String DEFAULT_ISSUER = "REATHIN"; private static final Long DEFAULT_EXPIRE_TIME = 7*24*60*60L; public String createToken(Map<String, Object> dataMap){ return createToken(dataMap, DEFAULT_SECRET); } public String createToken(Map<String, Object> dataMap, String secret){ // 指定使用的加密算法 Algorithm algorithm = Algorithm.HMAC256(secret); return JWT.create() .withClaim(DEFAULT_DATA_KEY, dataMap) .withIssuer(DEFAULT_ISSUER) .withIssuedAt(new Date()) .withExpiresAt(new Date(System.currentTimeMillis() + DEFAULT_EXPIRE_TIME * 1000)) .withJWTId(UUID.randomUUID().toString()) .sign(algorithm); } public Map<String, Object> parseToken(String token){ return parseToken(token, DEFAULT_SECRET); } public Map<String, Object> parseToken(String token, String secret){ // 指定使用的加密算法 Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); DecodedJWT decodedJWT = jwtVerifier.verify(token); return decodedJWT.getClaim(DEFAULT_DATA_KEY).asMap(); } }
JWT优缺点
优点:
- 无状态性(Stateless):JWT包含了所有用户的必要信息,服务器不需要存储用户的会话信息,因此可以轻松地扩展应用程序。
- 跨域支持(Cross-Origin Support):JWT可以在跨域场景下使用,因为它可以通过HTTP头部进行传递。
- 安全性(Security):JWT可以使用签名和加密来验证发送方的身份和确保数据的完整性。
- 灵活性(Flexibility):JWT可以用于各种场景,包括身份验证和信息交换。
缺点:
- 无法撤销(Non-Revocable):一旦JWT被签发,就无法撤销,除非设置短期过期时间。
- 增加网络负担(Increased Network Overhead):由于JWT包含了用户信息,因此会增加网络传输的负担。
- 潜在安全风险(Potential Security Risks):如果JWT被盗取,攻击者可以获得用户的所有信息,因此需要谨慎存储和传输JWT。
- 不适合存储敏感信息(Not Suitable for Storing Sensitive Information):由于JWT可以被解码,因此不适合存储敏感信息,如密码等。
原文地址:https://mp.weixin.qq.com/s/gk3XVF4rPrMMVay6kYii_w