JWT:Json Web Token快速入手

什么是JWT

  1. 起源:
    了解一门技术,应当从为什么产生开始了解比较好,JWT主要用于用户登录鉴权。解决分布式、单点登录,用户认证问题。
    认证技术还有:session认证,token认证…

  2. 描述:
    1、客户端:用户使用账号、密码发送登录请求,
    服务端:查询数据库验证当前用户是否存在,存在,生成token返回给客户端
    2、客户端:将返回的token存储到本地
    3、客户端:请求一个查询功能(在request里携带存储的token字符串),
    服务端:解析request中携带的token是否正确,正确,返回查询数据,错误,返回错误信息,
    客户端:正确,则展示数据,错误,跳转登录页面

  3. 简单来说就是一种认证机制,让后台知道该请求是来自于授信客户端。如图:
    在这里插入图片描述

JWT数据结构

jwt生成的字符串格式

xxx.yyy.zzz
Header.PayLoad.Signature
//xxx对应:jwt头(Header)
//yyy对应:有效负荷(PayLoad)
//zzz对应:签名(Signature)
  1. Header
    对应xxx,它是一个描述JWT原生的JSON对象,如下

    {
        "alg": "HS256",
        "typ": "JWT"
    }
    

    alg表示签名使用的算法,默认为HMAC SHA256(HS256),type为令牌类型,JWT统一写为JWT。
    最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

  2. PayLoad
    对应yyy,也是一个json对象,除了自定义需要传递的数据外,还有七个默认的字段。
    分别是,iss:发行人、exp:到期时间、sub:主题、aud:用户、nbf:在此之前不可用、iat:发布时间、jti:JWT ID用于标识该JWT。

    {
    	// 默认字段
        "sub": "主题",
    	// 自定义字段
        "user": "xiao.hei",
    	"id": "1"
    }
    

    需要注意的是,默认情况下JWT是未加密的,任何人都可以解读其内容,因此如果一些敏感信息不要存放在此,以防信息泄露

    JSON对象也使用Base64 URL算法转换为字符串保存。

  3. Signature
    对应zzz,对应签名,生成方式,首先在代码里自定义一个密匙,该密匙仅存在于服务器中,保证不让用户知道(密匙泄露,会造成破解登录问题),然后使用Header指定的算法对Header和Payload进行计算,然后算出一个签名哈希,也就是Signature

    验证token操作:例用JWT前两端,用一套哈希算法和同一个密匙计算一个签名值,然后把计算的签名和收到的JWT第三段比较,相同则认证通过。

JWT优点

  • json格式的通用性,使其可以跨语言
  • 可以在payload存储一些非敏感信息
  • 便于传输,jwt结构简单,字节占用小
  • 不需要在服务端保存会话信息,易于应用扩展。

JWT缺点

  • 安全性无法保证,所以jwt的PayLoad不能存储敏感信息,因为PayLoad并没有加密,只是用Base64编码而已。
  • 无法中途放弃,因为一旦签发了一个jwt,那么在到期前始终有效,如果用户信息更新了,只能等旧的jwt到期后重新签发一个。
  • 续期问题,当签发一个jwt后,客户一直在操作页面,按理jwt应一致有效,但当jwt有效期过了,用户需要重新登录。

JWT项目中实操(单服务中)ps:及拦截器实现拦截

  1. 导入maven: 使用springboot+mybatis-plus+mysql来实操
  2. <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
       <!-- <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency> -->
    
        <!-- jwt依赖 -->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.0.0</version>
        </dependency>
    
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

3. 操作相关:

yml配置,修改数据库ip及库
server:
  port: 80

spring:
  datasource:
    username: root
    password: p@ssW0rd
    url: jdbc:mysql://lcoalhost:3306/heiaxin?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true
    driver-class-name: com.mysql.cj.jdbc.Driver


启动类
@SpringBootApplication
@MapperScan("com.heiaxin.jwtproject.mapper")  // 配置自己的mapper扫描路径
public class JwtprojectApplication {

    public static void main(String[] args) {
        SpringApplication.run(JwtprojectApplication.class, args);
    }

}
JWT工具类
package com.heiaxin.jwtproject.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.heiaxin.jwtproject.entity.User;

import java.util.Calendar;

/**
 * json web token工具类
 */
public class JwtUtils {
	// 密匙
    private static final String SIGN = "hfahdfHLFHASKLFH4636990";



    /**
     * 根据用户对象生产token
     */
    public static String getToken(User user) {
        // 设置过期时间
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 7);

        // 创建jwt builder
        JWTCreator.Builder builder = JWT.create();

        // 设置token,第二部分存储的值
        builder.withClaim("username", user.getUName());
        builder.withClaim("id", user.getId());

        // 设置过期时间
        String token = builder.withExpiresAt(cal.getTime()).sign(Algorithm.HMAC256(SIGN));


        return token;
    }

    /**
     * 验证token合法性,及获取token中保存的用户基本信息
     */
    public static DecodedJWT verify (String token) {
        return JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
    }
}

控制器
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    UserService userService;

    @GetMapping("/findAll")
    public Map<String, Object> findALl() {
        Map<String, Object> result = new HashMap<>();
        User user = userService.getById(1);
        String token = JwtUtils.getToken(user);
        System.out.println("当前token值====>" + token);
        DecodedJWT verify = JwtUtils.verify(token);
        System.out.println(verify.getClaim("id"));
        System.out.println("token转译===> " + verify.toString());
        result.put("token", token);
        result.put("state", true);
        result.put("msg", "登录成功");
        return result;
    }

    @PostMapping("/test")
    public Map<String, Object> test(String token) {
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "认证成功!");
        result.put("state", true);
        return result;
    }
}
自定义拦截器

public class JWTInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map<String, Object> result = new HashMap<>();
        String token = request.getHeader("token");
        try {
            DecodedJWT verify = JwtUtils.verify(token);
            System.out.println("获取token,payLoad中的用户id====》" + id);
            return true;
        } catch (SignatureVerificationException e) {
            result.put("msg", "无效签名!");
            e.printStackTrace();
        } catch (TokenExpiredException e) {
            result.put("msg", "token过期!");
            e.printStackTrace();
        } catch (AlgorithmMismatchException e) {
            result.put("msg", "token算法不一致!");
            e.printStackTrace();
        } catch (Exception e) {
            result.put("msg", "token无效");
            e.printStackTrace();
        }
        // 将有效的token写回response
        // 将map 转为json jackson
        String json = new ObjectMapper().writeValueAsString(result);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

使自定义拦截器生效

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor()) // 添加自定义拦截器
                .addPathPatterns("/user/test")  // 需要走拦截器的接口
                .excludePathPatterns("/user/login"); // 不需要走拦截器的接口
    }
}

测试
可以正常get到token

在这里插入图片描述

测试test
将get到的token,带入到post请求的header中

请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值