-
JWT流程
- 客户端向服务器发起登陆请求,post登陆数据
- 服务端验证身份,将用户标识符打包生成 JWT, 并且返回给客户端
- 客户端发起获取用户资料请求,把刚刚拿到的 JWT 一起发送给服务器
- 服务器发现数据中有 JWT ,进行验证
- 服务器返回该用户的用户资料
-
JWT分析
-
头部 Header
头部有两部分信息,形式如下:
{ "alg": "RS256", "typ": "JWT" }
alg: 声明加密的算法
typ: 声明类型
然后对该json进行base64编码,成为Header
-
有效载荷 Payload
该部分有三种声明,分别是registered,public,private。形式同上。
- Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。JWT指定七个默认字段供选择。
iss:发行人
exp:到期时间
sup:主题
aud:用户
nbf:在此之前不可用
iat:发行时间
jti:JWT ID用于标识该JWT
- Public claims : 可以随意定义。
- Private claims : 用于在同意使用它们的各方之间共享信息,并且不是注册的或公开的声明。
然后对该json进行base64编码,成为Payload
-
签名 Signature
签名是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。操作如下:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
在计算出签名后,将JWT头部,有效载荷和签名的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象了。
-
-
实例
-
引入maven依赖
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency>
-
编写JWT工具类
public class JwtUtils { /** * 签发JWT * @param id * @param subject 可以是JSON数据 尽可能少 * @param ttlMillis * @return String * */ public static String createJWT(String id, String subject, long ttlMillis) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); SecretKey secretKey = generalKey(); JwtBuilder builder = Jwts.builder() .setId(id) .setSubject(subject) // 主题 .setIssuer("user") // 签发者 .setIssuedAt(now) // 签发时间 .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙 if (ttlMillis >= 0) { long expMillis = nowMillis + ttlMillis; Date expDate = new Date(expMillis); builder.setExpiration(expDate); // 过期时间 } return builder.compact(); } /** * 验证JWT * @param jwtStr * @return */ public static CheckResult validateJWT(String jwtStr) { CheckResult checkResult = new CheckResult(); Claims claims = null; try { claims = parseJWT(jwtStr); checkResult.setSuccess(true); checkResult.setClaims(claims); } catch (ExpiredJwtException e) { checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE); checkResult.setSuccess(false); } catch (SignatureException e) { checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL); checkResult.setSuccess(false); } catch (Exception e) { checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL); checkResult.setSuccess(false); } return checkResult; } public static SecretKey generalKey() { byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT); SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES"); return key; } /** * * 解析JWT字符串 * @param jwt * @return * @throws Exception */ public static Claims parseJWT(String jwt) throws Exception { SecretKey secretKey = generalKey(); return Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); } }
-
使用(测试例子)
public class LoginController { @Autowired UserRepository userRepository; @ApiOperation(value="用户登陆") @RequestMapping(value="login",method = RequestMethod.POST) public ReturnVo login(String username, String password,HttpServletResponse response) { User user = userRepository.findByUsername(username); if(user!=null){ if(user.getPassword().equals(password)){ //把token返回给客户端-->客户端保存至cookie-->客户端每次请求附带cookie参数 String JWT = JwtUtils.createJWT("1", username, SystemConstant.JWT_TTL); return ReturnVo.ok(JWT); }else{ return ReturnVo.error(); } }else{ return ReturnVo.error(); } } @ApiOperation(value="获取用户信息") @RequestMapping(value="description",method = RequestMethod.POST) public ReturnVo description(String username) { User user = userRepository.findByUsername(username); return ReturnVo.ok(user.getDescription()); } }
-