隐藏页面特效

Json Web Token

1|0什么是Json Web Token


JWT代表JSON Web Token,是一种用于在网络应用中传递信息的安全、紧凑的标准。它主要用于身份验证和授权,并且被广泛用于前后端分离的应用和单点登录系统。

JWT由三部分组成,通过点号(.)分隔,分别是:

  1. Header(头部):包含了两部分信息,令牌的类型(通常是"JWT")和所使用的加密算法,例如HMAC SHA256或RSA。
  2. Payload(负载):也称为Claims(声明),包含了一些实际需要传递的数据。这部分数据可以是预定义的标准声明(例如用户ID、过期时间等),也可以是自定义的声明。
  3. Signature(签名):使用指定的算法对Header和Payload进行签名,以确保令牌的完整性和真实性。签名需要使用一个秘钥,这样服务器可以使用秘钥来验证签名,从而确认该令牌的合法性。

在用户进行登录认证成功后,服务器会生成一个JWT并返回给客户端。客户端在后续的请求中携带这个JWT作为认证凭证,服务端通过验证JWT的签名来确定用户的身份和权限。由于JWT是自包含的,服务端不需要在数据库中查询用户信息,从而减轻了服务器的负担,并且提高了性能和可扩展性。

需要注意的是,由于JWT是基于Base64编码的,所以虽然它是安全的,但是不应该在JWT中存储敏感信息,因为Base64编码可以被解码。如果需要在JWT中传递敏感信息,应该对其进行加密处理。

2|0Json web Token的应用场景


  • Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
  • Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWT可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

3|0基于Token的身份认证 与 基于服务器的身份认证


  1. 基于服务器的身份认证

    • 传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。
    • Sessions : 每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。
    • Scalability : 由于Session是在内存中的,这就带来一些扩展性的问题。
    • CORS : 当我们想要扩展我们的应用,让我们的数据被多个移动设备使用时,我们必须考虑跨资源共享问题。当使用AJAX调用从另一个域名下获取资源时,我们可能会遇到禁止请求的问题。
    • CSRF : 用户很容易受到CSRF攻击。
  2. JWT与Session的异同点

  • 它们都是存储用户信息,然而,Session是在服务器端的,而JWT是在客户端的。
  • Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。
  • JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。
  • Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

4|0Json Web Token的认证流程


(https://images.cnblogs.com/cnblogs_com/-xyk/1824054/o_230801051515_Snipaste_2023-08-01_13-14-01.png)

5|0Json Web Token的使用


  1. 引入依赖

    <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.3.0</version> </dependency>
  2. JWT的简单使用

class Demo1ApplicationTests { private String tokenStr = "token-JWT"; // 创建 JSON Web Token (JWT) 的方法,其中包含了用户名、用户ID和过期时间 String createJWT() { Calendar calendar = Calendar.getInstance(); // 将当前时间增加 150 秒(2 分钟30秒) calendar.add(Calendar.SECOND, 150); return JWT.create() .withClaim("username", "jack") // 添加一个名为 "username" 的声明,值为 "jack" .withClaim("userid", 1) // 添加一个名为 "userid" 的声明,值为 1 .withExpiresAt(calendar.getTime()) // 将令牌的过期时间设置为计算后的时间 .sign(Algorithm.HMAC256(tokenStr)); // 使用 HMAC256 算法和给定的 tokenStr 对令牌进行签名 } @Test void TestJWT() { System.out.println(createJWT()); // 为了测试目的,将生成的 JWT 打印到控制台 // 使用相同的 tokenStr 验证 JWT 并获取解码后的令牌 JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenStr)).build(); DecodedJWT verify = verifier.verify(createJWT()); System.out.println(verify.getClaim("username").asString()); // 打印解码后的令牌中的 "username" 声明 System.out.println(verify.getClaim("userid").asInt()); // 打印解码后的令牌中的 "userid" 声明 } }
  1. JWT工具类的封装

    public class JWTUtil { private static final String SIGN = "secretKey"; public static String getToken(Map<String,String> map){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.DATE,3); JWTCreator.Builder builder = JWT.create(); map.forEach((k,v)->{ builder.withClaim(k,v); }); String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SIGN)); return token; } public static DecodedJWT verify(String token){ return JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token); } }
  2. 创建拦截器

    public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); System.out.println(token); Map<String,Object> map = new HashMap<>(); try { JWTUtil.verify(token); map.put("state",true); map.put("msg","认证成功"); return true; }catch (SignatureVerificationException e){ map.put("msg","无效签名"); e.printStackTrace(); }catch (TokenExpiredException e){ map.put("msg","token过期"); e.printStackTrace(); }catch (AlgorithmMismatchException e){ map.put("msg","算法不一致"); e.printStackTrace(); }catch (Exception e){ map.put("msg","token无效"); e.printStackTrace(); } map.put("state",false); String json = new ObjectMapper().writeValueAsString(map); response.setContentType("application/json;charset=utf-8"); response.getWriter().write(json); return false; } }
  3. 配置拦截器

    @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new JwtInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/user"); } }

__EOF__

本文作者keep on going,never give up
本文链接https://www.cnblogs.com/-xyk/p/17600406.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   彼时听风  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示