jwt的一些介绍
jwt能做什么jwt的组成结构简单使用描述,
在这里插入图片描述在这里插入图片描述在这里插入图片描述代码中使用演示
添加JWT的依赖 以及项目依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--jwt的依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.8.3</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.3</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.5.RELEASE</version>
            </plugin>
        </plugins>
    </build>

application.yml配置文件

server:
  port: 8080
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
    username: root
    password: root
mybatis:
  type-aliases-package: com.test.jwtToken.entity   #包映射
  configuration:
    map-underscore-to-camel-case: true   #驼峰

controller代码

/**
 * 测试使用session生成token信息给浏览器端,下次浏览器访问就会携带此信息在cookie中.这是以前的校验用户的方式
 */
@RestController
public class SessionTokenApplication {
    @GetMapping("/test")
    public String sessionToken(HttpServletRequest request) {
        request.getSession().setAttribute("userId", UUID.randomUUID());
        return "ok";
    }

    /**
     * 用户登录的接口,校验数据库之后,调用token工具类生成token返回客户端
     *
     * @param user  用户信息
     * @return 返回的信息
     */
    @Autowired
    private UserService userService;
    @PostMapping("/login")
    public Map<String, String> login(@RequestBody User user) {
        User userDb = userService.login(user);
        if (userDb == null) {
            throw new RuntimeException("用户不存在");
        }
        //用户校验成功
        HashMap<String, String> map = new HashMap<>();
        map.put("userName", userDb.getName());
        String token = jwtUtil.getToken(map);
        HashMap<String, String> resultMap = new HashMap<>();
        resultMap.put("state", "认证成功");
        resultMap.put("token", token);
        return resultMap;
    }

    /**
     * 请求时候带着token,对token进行解析,正确返回成功信息,不成功,抛出对应的异常
     * @param token   token令牌信息
     * @return          验证的信息
     */
    @PostMapping("/verify")
    public Map<String,Object> verify(String token) {
        HashMap<String, Object> map = new HashMap<>();
        try {
            //调用token解析的工具类进行解析
            DecodedJWT verifyToken = jwtUtil.verifyToken(token);
            //解析成功,返回成功的信息
            map.put("state", true);
            map.put("msg", "认证成功!");
            return map;
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msp", "签名不一致异常");
        } catch (TokenExpiredException e) {
            e.printStackTrace();
            map.put("msg", "令牌过期异常");
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg", "算法不匹配异常");
        } catch (InvalidClaimException e) {
            e.printStackTrace();
            map.put("msg", "失效的payload异常");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg", "token无效");
        }
        map.put("state", false);
        return map;
    }

    /**
     * 拦截器拦截校验token
     * @param user
     * @return
     */
    @GetMapping("/interceptorVerify")
    public String jwtInterceptorVerify(@RequestBody User user) {
        //拦截器会拦截所有请求,此处进行正常的业务逻辑即可
        //查询用户名是否存在
        User userDb = userService.login(user);
        if (userDb == null) {
            return "用户不存在";
        }
        return "用户存在";
    }
}

service接口

public interface UserService {
    User login(User user);
}

serviceImpl接口实现类

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public User login(User user) {
        User userDb = userMapper.login(user);
        return userDb;
    }
}

mapper接口

public interface UserMapper {
    User login(User user);
}

mapper的xml映射

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--PUBLIC:头文件约束,告知此文件是什么文件-->
<!--namespace:映射的命名空间为,接口的相对地址-->
<mapper namespace="com.test.jwtToken.mapper.UserMapper">
    <select id="login" resultType="User">
        select * from `user` where `name`= #{name} and `password`=#{password}
    </select>
</mapper>

实体类

@Data
public class User {
    private Integer id;
    private String name;
    private String password;
}

JWT生成token 和 解析token 的工具类

public class jwtUtil {
    //秘钥加密解密都需要用到,所以定义成静态常量
    public static final String SIGNATURE = "miyao";

    /**
     * 生成token
     * @param map payload中需要放置的相关非敏感信息
     * @return    返回的生成的token信息
     */
    public static String getToken(Map<String,String> map) {
        //设置一个时间,作为令牌的过期时间 ,设置过期时间为7天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 7);

        //创建jwt builder
        JWTCreator.Builder builder = JWT.create();
        //遍历map集合,将信息放到payload中
        map.forEach((k,v)->{
            builder.withClaim(k,v);  //payload信息
        });
        //header信息可以省略,因为默认已经有算法和类型了,也可以在headerMap中设置算法
        HashMap<String, Object> headerMap = new HashMap<>();
        String token = builder.withHeader(headerMap)     //header信息
                .withExpiresAt(calendar.getTime()) //token过期时间
                .sign(Algorithm.HMAC256(SIGNATURE));//签名
        return token;
    }

    /**
     * 验证token DecodedJWT 为解密之后的对象 可以获取payload中添加的数据
     */
    public static DecodedJWT verifyToken(String token) {
        //进行token的校验,注意使用同样的算法和同样的秘钥
        return JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
    }

    /**
     * 获取token中payload中的添加的参数 演示
     * @return
     */
    public static DecodedJWT getTokenPayloadParam(String token) {
        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGNATURE)).build().verify(token);
        //Map<String, Claim> claims = verify.getClaims(); //获取payload中所有的参数
        //verify.getClaim("userName").asString();  //通过key获取value,转成对应的类型
        return verify;
    }
}

每个方法都进行token校验太过麻烦,
设置拦截器,在方法前进行token解析校验

/**
 * 添加拦截器,拦截请求,校验token
 */
public class JWTInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HashMap<String, Object> map = new HashMap<>();
        String token = request.getHeader("token");  //从request中获取到请求头中的token,进行解析校验
        try {
            jwtUtil.verifyToken(token);//调用token解析的工具类进行解析
            return true;  //请求放行
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg", "签名不一致异常");
        } catch (TokenExpiredException e) {
            e.printStackTrace();
            map.put("msg", "令牌过期异常");
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg", "算法不匹配异常");
        } catch (InvalidClaimException e) {
            e.printStackTrace();
            map.put("msg", "失效的payload异常");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg", "token无效");
        }
        //map异常的数据要返回给客户端需要转换成json格式  @ResponseBody 内置了jackson
        String resultJson = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().print(resultJson);
        return false;  //异常不放行
    }
}

设置拦截器的拦截规则,放行规则

@Configuration
public class interceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/interceptorVerify/**")   //拦截所有的路径
                .excludePathPatterns("/login/**"); //放行login目录下的,因为生成token的方法拦截就无法生成token了
    }
}

测试类中进行jwt生成token 与解析token的单独测试

public class JwtTokenTest {
    /**
     * 令牌的获取
     * 测试生成jwt的token令牌三部分组成
     * header(加密算法,类型) . payload(负载,可以不重要可以用得到的用户信息) . signature(签名,前两部跟base64加密和自己的秘钥)
     */
    @Test
    public void jwtToken() {
        HashMap<String, Object> map = new HashMap<>();//header中需要传递的map,无内容时使用jwt默认值
        //设置一个时间,作为令牌的过期时间 ,设置过期时间为60秒
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 60);

        String token = JWT.create().withHeader(map)//header中已经有默认的算法和类型
                .withClaim("userId", 123456) //payload负载
                .withClaim("userName", "zhangsan") //payload可以传递多个
                .withExpiresAt(calendar.getTime())  //令牌不是无限期的,设置令牌的过期时间
                .sign(Algorithm.HMAC256("miyao"));//签名设计加密算法,还有设置自己的秘钥

        System.out.println(token);
    }

    /**
     * 解析token,注意有效期内
     */
    @Test
    public void verifyTest() {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("miyao")).build();
        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6InpoYW5nc2FuIiwiZXhwIjoxNjIyMTIwNzgzLCJ1c2VySWQiOjEyMzQ1Nn0.wCobBUz5oRVmeaTBT5Omo_Ab3iTid8JrXRfqmxC-wqs");
        //解析完成之后可以获取payload负载中自包含放置的信息
        System.out.println(verify.getClaims());
        System.out.println(verify.getClaim("userId").asInt());
        System.out.println(verify.getClaim("userName").asString());
        //获取过期时间
        System.out.println(verify.getExpiresAt());

    }
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐