JWT令牌应用

75 阅读4分钟

1、JWT令牌 令牌:就是用户身份的的标识,其本质是一个字符串,令牌的的形式有很多,我们一般使用JWT令牌 JWT令牌:全称JSON Web Token ,定义了一种简洁的,自包含的格式,用于在通信双方以json数据格式安全的传输信息。 由于数字签名的存在,这些信息时可靠的。

  • 简洁:是指jwt就是一个简单的字符串。可以在请求参数或者是请求头当中直接传递。
  • 自包含:指的是jwt令牌,看似是一个随机的字符串,但是我们是可以根据自身的需求在jwt令牌中存储自定义的数据内容。如:可以直接在jwt令牌中存储用户的相关信息。
  • 简单来讲,jwt就是将原始的json数据格式进行了安全的封装,这样就可以直接基于jwt在通信双方安全的进行信息传输了。 • JWT的组成:(JWT令牌由三个部分组成,三个部分之间使用,英文的的点来分割) 第一部分:头(Header),记录令牌类型,签名算法 第二部分:载荷(Payload),携带一些自定义信息,默认信息等。 第三部分:签名(Signature),防止Token被篡改,确保安全性。将header,payload,指定秘钥加入,使用Base64编码。 为什么安全:签名的目的就是为了防止JWT令牌被篡改,而正是因为jwt令牌最后一个部分数字签名的存在,所以整个就jwt令牌是非常安全可靠的。一旦jwt令牌中任何一个部分、任何一个部分被篡改了,整个令牌在校验的时候都会失败,所以他是非常安全可靠的

2、生成和校验 首先要在项目配置文件中导入JWT依赖。

io.jsonwebtoken jjwt 0.9.1 代码实现 JWT令牌的生成 public void testGenJwt() { Map claims = new HashMap<>(); claims.put("id", 10); claims.put("username", "itheima");
String jwt = Jwts.builder().signWith(SignatureAlgorithm.HS256, "aXRjYXN0")
    .addClaims(claims)
    .setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))
    .compact();

System.out.println(jwt);

} eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk 输出的结果就是JWT格式的令牌。

JWT令牌的校验 @Test public void testParseJwt() { Claims claims = Jwts.parser().setSigningKey("aXRjYXN0") .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MTAsInVzZXJuYW1lIjoiaXRoZWltYSIsImV4cCI6MTcwMTkwOTAxNX0.N-MD6DmoeIIY5lB5z73UFLN9u7veppx1K5_N_jS9Yko") .getBody(); System.out.println(claims); } 3、如何拦截请求从而判断令牌的合法性? ##Filter过滤器: JavaWeb三大组件(Servlet,Filter,Listener)之一。它可以把对资源的请求拦截下来,从而实现一些特殊的功能。 使用了过滤器之后,想要访问web服务器的资源,必须要经过过滤器,过滤器处理完毕之后,才可以访问对应的资源。 使用过滤器的操作步骤 1)定义一个类实现Filter接口,并重写所有的方法; 2)配置过滤器:Filter类上加上@WebFilter注解,配置拦截资源的路径。引导类上家@ServletConponentScan注解开启Servlet组件支持 public class DemoFilter implements Filter { //初始化方法, web服务器启动, 创建Filter实例时调用, 只调用一次 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init ..."); }

//拦截到请求时,调用该方法,可以调用多次
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
    System.out.println("拦截到了请求...");
}

//销毁方法, web服务器关闭时调用, 只调用一次
public void destroy() {
    System.out.println("destroy ... ");
}

} 基于以上使用登录检验过滤器,步骤:

  1. 获取请求url
  2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行
  3. 获取请求头中的令牌(token)
  4. 判断令牌是否存在,如果不存在,响应 401
  5. 解析token,如果解析失败,响应 401
  6. 放行 代码实现 package com.itheima.filter;

import com.itheima.utils.JwtUtils; import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpStatus; import org.springframework.util.StringUtils; import java.io.IOException;

/**

  • 令牌校验过滤器 / @Slf4j @WebFilter(urlPatterns = "/") public class TokenFilter implements Filter {

    @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //1. 获取请求url。 String url = request.getRequestURL().toString();

     //2. 判断请求url中是否包含login,如果包含,说明是登录操作,放行。
     if(url.contains("login")){ //登录请求
         log.info("登录请求 , 直接放行");
         chain.doFilter(request, response);
         return;
     }
    
     //3. 获取请求头中的令牌(token)。
     String jwt = request.getHeader("token");
    
     //4. 判断令牌是否存在,如果不存在,返回错误结果(未登录)。
     if(!StringUtils.hasLength(jwt)){ //jwt为空
         log.info("获取到jwt令牌为空, 返回错误结果");
         response.setStatus(HttpStatus.SC_UNAUTHORIZED);
         return;
     }
    
     //5. 解析token,如果解析失败,返回错误结果(未登录)。
     try {
         JwtUtils.parseJWT(jwt);
     } catch (Exception e) {
         e.printStackTrace();
         log.info("解析令牌失败, 返回错误结果");
         response.setStatus(HttpStatus.SC_UNAUTHORIZED);
         return;
     }
    
     //6. 放行。
     log.info("令牌合法, 放行");
     chain.doFilter(request , response);
    

    }

} ##拦截器Interceptor 拦截器是一种动态拦截方法调用的机制,类似于过滤器; 拦截器是Spring框架中提供的,用来动态拦截控制器方法的执行; 拦截的作用:拦截请求,在指定方法调用前后,根据业务需要执行预先设定的代码。

拦截器的使用步骤: 1)定义拦截器,自定义类实现HandlerInterceptor接口,重写所有方法,注意这个类不能是最终类,因为Interceptor是基于子类操作的 2)注册配置拦截器