您现在的位置是:首页 > 名人名句

JWT(JSON Web Token )详解及实例

作者:焦糖时间:2024-04-14 18:50:32分类:名人名句

简介  文章浏览阅读4.2k次,点赞13次,收藏14次。JSON Web Token (JWT)详解_io.jsonwebtoken

点击全文阅读

目录

一、什么是 JWT ?

二、什么时候使用 JWT ?

三、JWT 格式

1、Header

2、Payload

3、Signature

4、 JWT实现:


官网

官网 JSON Web Tokens - jwt.ioRFC 7519文档 RFC 7519: JSON Web Token (JWT)

一、什么是 JWT ?

JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。
JWT可以使用密码(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

加签后的token 能够使用 JWT 里的算法验证 json 的完整性.

二、什么时候使用 JWT ?

授权信息交换使用方式:服务端根据规范生成一个令牌(token),并且发放给客户端(保存在客户端)。此时客户端请求服务端的时候就可以携带者令牌,以令牌来证明自己的身份信息。前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)

JWT优势
    简洁:可以通过URL、POST参数或者在HTTP Header发送,因为数据量小,传输速度也很快
    自包含:负载中包含了所有用户所需要的信息,避免了多次查询数据库
    因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式       都支持
    不需要在服务端保存会话信息,特别适合用于分布式微服务。
    更适合用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时使用token认证方       式会简单很多
     单点登录友好:由于cookie无法跨域,难以实现单点登录。但是,使用token进行认证的话,            token可以被保存在客户端的任意位置的内存中,不一定是cookie,所以不依赖cookie,不会          存在这些问题
 

三、JWT 格式

使用逗号分隔的三部分 :

HeaderPayloadSignature
token 格式:xxxxx.yyyyy.zzzzz

1、Header

Header 通常由 token 类型和签名算法名两部分组成.是token的第1部分
例如:

{
"alg": "HS256", // 签名算法
"typ": "JWT" // token类型
}

然后, 这个JSON 使用 Base64Url 编码后放到 JWT 的第1部分.

2、Payload

Payload 是token的第2部分.包含了一些声明(claims).声明的名字必须是唯一的.
claims 是包含了 用户数据和其他数据的陈述,

有三种类型的声明:

Registered Claim Name
预定义好的一些声明(如果有需要就使用,没需要可不使用): "iss""sub""aud""exp""nbf""iat""jti"

更多参见 JSON Web Token (JWT)

Public Claim Names
公共的声明,可以预先定义在 IANA JSON Web Token Registry 中,或者定义在1个能解决名字冲突的地方.

Private Claim Names
双方共享数据使用的私有名字.既不在 Registered Claim Name 也不在 Public Claim Names 中.

payload 示例

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

JSON 

然后, 这个JSON 使用 Base64Url 编码后放到 JWT 的第2部分.

3、Signature

拿到编码后的 header 和 编码后的 payload 使用 密码进行签名.

使用 HMAC SHA256 加签示例:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

Signature需要使用编码后的header和payload以及我们提供的一个秘钥,然后使用header中指定的签名算法进行签名,签名的作用是保证JWT没有被篡改过

HMACSHA256(base64UrlEncode(header)+“.”+base64UrlEncode(payload),secret)

实际上是对头部信息和负载内容进行签名,防止内容被篡改,如果有人对头部以及负载内容解码后进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务器端会判断出新的头部和负载形成的签名和JWT上附带的签名是不一样的。如果要对新的头部和负载进行签名,由于不知道服务器加密时使用的秘钥,得出来的结果也是不一样的

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。

4、 JWT实现:

  1、依赖引入

        <dependency>            <groupId>io.jsonwebtoken</groupId>            <artifactId>jjwt</artifactId>            <version>${jwt-jsonwebtoken.version}</version>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>RELEASE</version>        </dependency>

2、生成Token 

// 签名密钥 private static final String SECRET = "!Doker$";public String createToken(Map<String, Object> claims, String subject) {        final Date createdDate = clock.now();        final Date expirationDate = calculateExpirationDate(createdDate);        return Jwts.builder()                .setClaims(claims)                .setSubject(subject)                .setIssuedAt(createdDate)                .setExpiration(expirationDate)                .signWith(SignatureAlgorithm.HS512, Algorithm.HMAC256(SECRET))                .compact();    }    private Date calculateExpirationDate(Date createdDate) {        return new Date(createdDate.getTime() + expiration * 1000);    }

3、刷新Token 

public String RefreshToken(String token) {        final Date createdDate = clock.now();        final Date expirationDate = calculateExpirationDate(createdDate);        final Claims claims = getAllClaimsFromToken(token);        claims.setIssuedAt(createdDate);        claims.setExpiration(expirationDate);        return Jwts.builder()                .setClaims(claims)                .signWith(SignatureAlgorithm.HS512, Secret)                .compact();    }

4、token发送给前端
传入当前用户的功能与用户信息,登录名生成token,写入response的返回头中,前端获取后保存在前端的本地缓存中,后续前端请求要把token放在头header里。

//登录成功之后List<Object> functs=(List<Object>) authResult.getAuthorities();//当前功能列表String loginName=authResult.getName();//登录名Users obj=(Users)authResult.getPrincipal();//用户信息String token=JwtUtil.createToken(loginName,functs,obj);//生成token  TOKEN_HEADER= Authorization TOKEN_PREFIX=Bearer token值response.setHeader(JwtUtil.TOKEN_HEADER,JwtUtil.TOKEN_PREFIX+token);response.setContentType("application/json;charset=utf-8");response.setStatus(HttpServletResponse.SC_OK); //个人编写的视图对象DTO dto=new DTO<>();dto.setCode("000000");dto.setMessage("认证通过");PrintWriter pw=response.getWriter();pw.write(JsonUtil.set(dto));//写入jsonpw.flush();//强制刷新pw.close();//关闭流

5、验证用户请求携带token

String header = request.getHeader(JwtUtil.TOKEN_HEADER); if (null == header || !header.toLowerCase().startsWith(JwtUtil.TOKEN_PREFIX)) {   // 如果头部 Authorization 未设置或者不是 basic 认证头部,则当前   // 请求不是该过滤器关注的对象,直接放行,继续filter chain 的执行   chain.doFilter(request, response);   return;} try {  String token = header.replace(JwtUtil.TOKEN_PREFIX, "");   // 验证token是否过期  if (JwtUtil.isExpiration(token)) {       throw new javax.security.sasl.AuthenticationException("token 验证不通过");} //檢查token是否能解析Users user = (Users) JwtUtil.getUser(token); if (null == user) {     throw new javax.security.sasl.AuthenticationException("token 验证不通过");} //验证成功

点击全文阅读

郑重声明:

本站所有活动均为互联网所得,如有侵权请联系本站删除处理

我来说两句