关于jwt token鉴权的一些理解

token 中文译 “令牌”,是一种由服务端生成的字符串,颁发给客户端使用的鉴权机制。
客户端获取到一个token后,以后无需带上用户名和密码,只需带上token即可。
身份认证论述:
HTTP是无状态协议,服务端并不清楚是谁请求了它,只有客户端带上用户的账号密码,服务端通过验证后才清楚到底是那个用户请求了它,本次请求完结后,再次请求又需要重新认证。
通用的解决办法是:用户第一次通过认证后,服务端生成一条记录,并将记录id放回给客户端,(类似与session_id),之后客户端每次请求带上这个id,服务端只需要检索这个id,找到了这条记录,就说明用户已经通过身份验证。
关于token认证的论述:
token认证的流程:用户第一次登录服务端,服务器根据用户的私有信息,时间戳,签名算法,私钥 通过算法生成token并返回给客户端,之后客户端请求只需要带上这个token即可,服务端只需对这个token进行解析,即可得知那个用户进行了操作。
私有信息: 一般为用户的信息,用户的标识等
时间戳: 当前时间
私钥: 这个比较重要,服务端自有信息。 生成token 解密时候需要它。就相当于一把锁的钥匙,用它锁上的信息,也只有用它才能解锁。不然客户端自己也可以生成token了
直接上代码:
在这里插入图片描述
JWTUtils.java

/**

  • ToKen工具类

  • JWT生成
    */
    @Component
    public class ToKenUtil {

    /**

    • 生成Jwt

    • 使用Hs256算法 私匙使用固定私钥

    • @param timeOut jwt过期时间

    • @return
      */
      public static String createJWT(long timeOut,Map claims) {

      //指定签名的时候使用的签名算法
      SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

      //生成JWT的时间
      long nowMillis = System.currentTimeMillis();
      Date now = new Date(nowMillis);

      //校验项
      claims.put(“admin”,true);

      //下面就是在为payload添加各种标准声明和私有声明了
      //这里其实就是new一个JwtBuilder,设置jwt的body
      JwtBuilder builder = Jwts.builder()
      //如果有私有声明,一定要先设置这个自己创建的私有的声明,
      // 这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
      .setClaims(claims)
      //设置jti(JWT ID):是JWT的唯一标识
      .setId(UUID.randomUUID().toString())
      //iat: jwt的签发时间
      .setIssuedAt(now)
      //JWT的主体。
      .setSubject(UUID.randomUUID().toString())
      //设置签名使用的签名算法和签名使用的秘钥
      .signWith(signatureAlgorithm, JwtConstants.SECRET);
      if (timeOut >= 0) {
      long expMillis = nowMillis + timeOut;
      Date exp = new Date(expMillis);
      System.out.println(new SimpleDateFormat(“yyyy-MM-dd HH:ss:mm”).format(exp));
      //设置过期时间
      builder.setExpiration(exp);
      }
      return builder.compact();
      }

    /**

    • 生成token
    • 超时默认5分钟
    • */
      public static String createJWT(Map claims){
      return createJWT(JwtConstants.TIME_OUT,claims);
      }

    /**

    • Token的解密

    • @param token 加密后的token

    • @return
      */
      public static Claims parseJWT(String token) {

      //得到DefaultJwtParser
      Claims claims = Jwts.parser()
      //设置签名的秘钥
      .setSigningKey(JwtConstants.SECRET)
      //设置需要解析的jwt
      .parseClaimsJws(token).getBody();
      return claims;
      }

    /**

    • 校验token

    • 异常为token过期

    • @param token

    • @return
      */
      public static Boolean isVerify(String token) {

      //得到DefaultJwtParser
      Claims claims = Jwts.parser()
      //设置签名的秘钥
      .setSigningKey(JwtConstants.SECRET)
      //设置需要解析的jwt
      .parseClaimsJws(token).getBody();

      if (claims.get(“admin”).equals(true)) {
      return true;
      }
      return false;
      }
      }

JwtConstants.java

/**

  • jwt相关配置
    */
    public class JwtConstants {

    //超时时间 60天
    public static long TIME_OUT = 1000 * 3600 * 24 * 60;
    //私钥
    public static String SECRET = “123456”;
    public static String TOKEN_KEY = “authentication”;
    //忽略的token验证
    public static List IGNORE_PERMISSION = CollectionUtil.newLinkedList("/api/login/getAccessToKen");

}

restApiInteceptor.java 拦截器

/**

  • Rest Api接口鉴权
    */
    public class RestApiInteceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (handler instanceof org.springframework.web.servlet.resource.ResourceHttpRequestHandler) {
    return true;
    }
    return check(request, response);
    }

    private boolean check(HttpServletRequest request, HttpServletResponse response) {
    if (JwtConstants.IGNORE_PERMISSION.toString().toUpperCase().contains(request.getServletPath().toUpperCase())) {
    return true;
    }
    final String authToken = request.getHeader(JwtConstants.TOKEN_KEY);
    if (authToken != null) {
    try {
    //验证token是否过期 包含验证jwt是否正确
    if(!ToKenUtil.isVerify(authToken)){
    throw new Exception();
    }
    } catch (ExpiredJwtException e) {
    //token超时
    RenderUtil.renderJson(response, LoginResponseData.toKenTimeOut());
    return false;
    }catch (Exception e) {
    //token解析失败
    RenderUtil.renderJson(response, LoginResponseData.invalidToKen());
    return false;
    }
    } else {
    //header没有带authentication字段
    RenderUtil.renderJson(response, LoginResponseData.noToKen());
    return false;
    }
    return true;
    }

}

webConfig.java

/**

  • web 配置类
    */
    @Configuration
    public class WebConfig implements WebMvcConfigurer {

    /**

    • 静态资源映射
      /
      @Override
      public void addResourceHandlers(ResourceHandlerRegistry registry) {
      /
      *
      • 设置映射资源
      • */
        registry.addResourceHandler(uploadResourceHandler).addResourceLocations(“file:///” + uploadPath);
        //本应用
        registry.addResourceHandler("/assets/**").addResourceLocations(“classpath:/assets/”);
        }

    /**

    • 增加对rest api鉴权的spring mvc拦截器
      /
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
      //对 /api/
      * 的请求进行拦截
      registry.addInterceptor(newRestApiInteceptor()).excludePathPatterns().addPathPatterns("/api/**");

    }

    /**

    • RequestContextListener注册
      */
      @Bean
      public ServletListenerRegistrationBean requestContextListenerRegistration() {
      return new ServletListenerRegistrationBean<>(new RequestContextListener());
      }

    /**

    • ConfigListener注册
      */
      @Bean
      public ServletListenerRegistrationBean configListenerRegistration() {
      return new ServletListenerRegistrationBean<>(new ConfigListener());
      }

}

大概流程如下:
① 客户端第一次登录,服务器根据用户的私有信息 时间戳 签名串 私钥 过期时间 生成token并返回到客户端,之后客户端请求时带上token令牌
② 由于服务端每次接到请求都要认证,故此将认证逻辑推荐写入拦截器,并在webConfig配置中加入此拦截器,若不是springBoot工程,可在web.xml里配置
③ 服务端每次接收到请求后,对请求进行拦截,获取token信息后进行解析,若解析成功则通过过。
解析不成功大致有,token超时 无效的token(即不是服务端生成的token)

理解有误的地方可留言指教

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值