JWT简单使用

JWT简单使用

一、概述

1.JWT是什么

​ JWT全称是JSON Web Token,通过JSON形式作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输,在数据传输过程中还可以完成数据加密、签名等相关处理。

2.JWT能做什么?

授权

​ 一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌的路由、服务和资源,单点登录是如今广泛使用JWT的一项功能。

信息交换

​ JWT是在各方之间安全地传输信息的好办法,因为可以对JWT进行签名,所以可以确保发件人是目标对象。

3.为什么要使用JWT?

​ 在之前的Java Web项目中我们都使用session进行用户登录验证,而session是存在服务器中的,当用户量大的时候会使效率降低,并且在分布式开发中session需要共享。而JWT当用户登录成功之后,token就会存在客户端中,每次访问接口都会在"Header"中带上token,后端统一验证。

二、JWT结构

​ JWT生成的token令牌是由三部分组成:Header(表头)、payLoad(有效负载)、signature(签名),因此token通常为:xxxxx.yyyyy.zzzzz,而后端判就是用signature来判断是否为正确的用户和用户是否过期。

1.Header

​ 表头通常由两部分组成:令牌的类型和所使用的签名算法,例如HMAC、SHA256或RSA。它会使用Base64编码组成JWT结构的第一部分。

【注意】:Base64是一种编码格式,是可以被反编译的。

//alg是所使用的签名算法,typ是JWT类型
{
    "alg": "HS256"
}	"typ": "JWT"
2.payLoad

​ 令牌的第二部分是有效负载,其中包含声明。声明是有关实体(用户)和其他数据的声明。同样,它也使用Base64编码的。

//payLoad中存储的是用户的信息
{
    "sub": "123456"
    "name": "zhangsan"
}
3.signature

​ 前面两部分都是用Base64进行编码的,即前端可以解开里面的信息,Signature需要编码后的header和payLoad以及我们提供的密匙,然后使用header中指定的算法进行签名,签名的作用是保证JWT没有被篡改过。

三、使用JWT

1.JWT代码

引入依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

生成token

//s为密匙也叫加密盐
    String s="!abc@ert";
    Calendar instance=Calendar.getInstance();
    //设置过期时间,单位为秒,
    instance.add(Calendar.SECOND,90);

    //生成令牌
    Map map=new HashMap();
    String token= JWT.create()
//                .withHeader(map)//添加header中的信息,是默认的,不加也可以
            .withClaim("username","zhangsan")//添加payLoad中的用户信息
            .withExpiresAt(instance.getTime())
            .sign(Algorithm.HMAC256(s));//设置签名,保密
    System.out.println(token);

生成结果

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJleHAiOjE2MzYxMjAxOTgsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ.
OykEg2oSwpG4Qpg6J43UG8l9tHbgq4FFMF-PyUXtKtc

根据令牌和签名解析数据

//需要将加密盐secret和签名算法(HMAC256)带上
        JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(secret)).build();
        //解析token
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzYxMjAxOTgsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ.OykEg2oSwpG4Qpg6J43UG8l9tHbgq4FFMF-PyUXtKtc");
        //获取用户名
        /**
         * 注意:
         *  1.如果用户信息当时存放的是int类型,需要用asInt输出,如下:
         *          verify.getClaim("usernameId").asInt();
         *  2.如果用户信息当时存放的是String类型,需要用asString输出,如下:
         *          verify.getClaim("usernameId").asString();
         */
        verify.getClaim("username");
        //获取过期时间
        verify.getExpiresAt();
2.JWT的工具类封装
public class JWTUtil {

    //加密盐/密匙
    private final static String secret="!abcdrl";

    //生成token,map中存入要放入payLoad中的用户信息
    public static String getToken(Map<String,String> map){
        Calendar instance=Calendar.getInstance();
        //设置过期类型和时间,一般选天
        instance.add(Calendar.DATE,5);

        //存入header、payload和signature生成token
        JWTCreator.Builder builder= JWT.create();
        //遍历map,将用户信息存入
        map.forEach((k,v)->{
            builder.withClaim(k,v);
        });
        String token = builder.withHeader(new HashMap<>())//可以不加,有默认值
                .withExpiresAt(instance.getTime())//指定过期时间
                .withClaim("username", "zhangsan")
                .withClaim("id", 5)
                .sign(Algorithm.HMAC256(secret));//传入密匙和加密标签的算法
        return token;
    }

    /**
     * 解析verify,可以直接拿到这个在service层进行处理获取用户信息
     * @param token
     * @return
     */
    public DecodedJWT verify(String token){
        JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(secret)).build();
        DecodedJWT verify = jwtVerifier.verify(token);
        return verify;
    }
}
3.SpringBoot整合JWT

只在controller层作演示

/**
 * 用户登录,登录成功获取token返回给前端
 * @param username
 * @param password
 * @return
 */
@RequestMapping("/user")
public String login(String username,String password){
    //假设数据库中的用户名和密码如下:
    String username_date="admin";
    String password_date="admin";
    if (username_date.equals(username) && password_date.equals(password)){
        Map<String,String> map=new HashMap();
        map.put("username",username_date);
        map.put("password",password_date);
        //获取token
        String token = JWTUtil.getToken(map);
        return token;
    }
    return null;
}


/**
 * 客户端访问接口都需要带一个token,检查成功之后返回数据
 * @param token
 * @return
 */
@RequestMapping("getInfo")
public Map getInfo(String token){
    System.out.println(token);
    JWTUtil jwtUtil=new JWTUtil();
    DecodedJWT verify = jwtUtil.verify(token);
    if (verify!=null){
        String username = verify.getClaim("username").asString();
        String password = verify.getClaim("password").asString();
        Map map=new HashMap();
        map.put("username",username);
        map.put("password",password);
        return map;
    }
    return null;
}

拦截器中整合

​ 使用拦截器之后就不用在每个代码中都验证token是否正确。

拦截器

public class JWTHandler implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求头中的令牌
        String token = request.getHeader("token");
        Map<String,Object> map=new HashMap<>();
        try{
            JWTUtil.verify(token);
        }catch (SignatureVerificationException e){
            e.printStackTrace();
            map.put("msg","无效签名");
        }catch (TokenExpiredException e){
            e.printStackTrace();
            map.put("msg","token过期");
        }catch (AlgorithmMismatchException e){
            e.printStackTrace();
            map.put("msg","token算法不一致");
        }catch (Exception e){
            map.put("msg","token失效");
        }
        map.put("state",false);//设置状态
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=utf-8");
        return false;
    }
}

拦截器配置

@Configuration
public class JWTConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTHandler())
                .addPathPatterns("/**") //拦截所有路径
                .excludePathPatterns("/login");//排除登录接口
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值