• JWT(2):JWT入门使用


    前言

    JWT如何生成token?
    token如何验签?
    springboot中如何使用JWT?

    如果你对JWT的概念不了解,建议先阅读JWT的介绍,以方便对JWT的构成有清晰的认识,当然这并不影响你对JWT的使用。
    详细可以查看 JWT(1): JWT介绍
    英文较好的可以查阅官方的介绍:https://jwt.io/introduction

    第一节 如何使用JWT

    1. 引入依赖

     
            
            <dependency>
                <groupId>com.auth0groupId>
                <artifactId>java-jwtartifactId>
                <version>4.0.0version>
            dependency>
    

    2. 生成token

      @Test
        public void testJWTCreate(){
    
            String token=createToken();
            System.out.println(token);
        }
    
        public String createToken(){
            Calendar instance=Calendar.getInstance();
            instance.add(Calendar.SECOND,60);
            //默认包header加密是HS256,通常不需要设置
    //        JWT.create().withHeader()
            HashMap<String,Object> map=new HashMap<>();
            String token= JWT.create()
                    .withHeader(map)
                    .withClaim("userId",1) //指定用户信息
                    .withClaim("name","xiaowang") //指定用户名
                    .withExpiresAt(instance.getTime()) //指定过期时间
                    .sign(Algorithm.HMAC256("%sabs*!3ja"));//签名
            return token;
        }
    

    运行结果
    在这里插入图片描述

    3. 解析token

    @Test
        public void testVerification(){
            String token=createToken();
            JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256("%sabs*!3ja")).build();
            DecodedJWT verify=jwtVerifier.verify(token);//解析jwt
            System.out.println(verify.getClaims());
        }
    

    运行结果
    在这里插入图片描述

    4. 常见异常

    在这里插入图片描述

    • SignatureVerificationException 签名异常
    • TokenExpiredException Token失效异常
    • JWTDecodeException JWT解析异常
    • InvalidClaimException 有效负载无效异常
    • AlgorithmMismatchException 签名算法不匹配

    5. 封装JWT方法

    package com.it2.springbootjwt.util;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTCreator;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.interfaces.DecodedJWT;
    
    import java.util.Calendar;
    import java.util.Map;
    
    /**
     * JWT
     */
    public class JWTUtils {
    
        /**
         * 密钥
         */
        private static final String SECRET = "FTIq]>h!>2H-zd_";
    
        /**
         * 生成token
         *
         * @param map
         * @param amount 有效期秒
         * @return
         */
        public static String createToken(Map<String, String> map, Integer amount) {
            Calendar instance = Calendar.getInstance();
            /**
             * 签名失效时间如果不传递,则默认7天
             */
            amount = (null == amount || amount < 1) ? 7 * 24 * 60 * 60 : amount;
            instance.add(Calendar.SECOND, amount);
            //默认包header加密是HS256,通常不需要设置
            JWTCreator.Builder builder = JWT.create();
            map.forEach((k, v) -> {
                builder.withClaim(k, v);
            });
            String token = builder.withExpiresAt(instance.getTime()) //指定过期时间
                    .sign(Algorithm.HMAC256(SECRET));//签名
            return token;
        }
    
        /**
         * 验签
         *
         * @param token
         */
        public static void vertifyToken(String token) {
            getTokenInfo(token);
        }
    
        /**
         * 获取token信息
         *
         * @param token
         */
        public static DecodedJWT getTokenInfo(String token) {
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            DecodedJWT verify = jwtVerifier.verify(token);//解析jwt
            return verify;
        }
    }
    

    第二节 JWT登录和验证

    1. 登录

    1. 首先,我们UserController实现登录
    package com.it2.springbootjwt.controller;
    
    import com.it2.springbootjwt.pojo.User;
    import com.it2.springbootjwt.service.UserService;
    import com.it2.springbootjwt.util.JWTUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @RestController
    @Slf4j
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @PostMapping("/user/login")
        public Map<String, Object> login( String username,String password) {
            log.info("用户名:{},密码:{}", username, password);
            Map<String, Object> map = new HashMap<>();
            try {
                User user2 = userService.login(username,password);
                Map<String, String> payload = new HashMap<>();
                payload.put("userid", user2.getId() + "");
                payload.put("username", user2.getUsername());
    
                String token = JWTUtils.createToken(payload, null);
                map.put("token", token);
                map.put("code", "ok");
                map.put("msg", "登录成功");
            } catch (Exception e) {
                map.put("code", "fail");
                map.put("msg", "登录失败");
            }
            return map;
        }
    }
    
    package com.it2.springbootjwt.pojo;
    import lombok.Data;
    @Data
    public class User {
    
        private Integer id;
        private String username;
        private String password;
    }
    
    1. 实现service,这里只是demo,所以写死service的实现,实际业务应当查询数据库进行验证。
      在这里插入图片描述
    2. 启动服务器,发起登录测试,可以看到生成了token。
      在这里插入图片描述

    2. 拦截器

    我们的业务在执行的时候,显然需要编写token是否有效,但是这明显不可能放在各个业务中去鉴定。
    所以我们需要使用拦截器,拦截器可以在业务执行前判断请求的token是否有效。

    1. 定义拦截器
    package com.it2.springbootjwt.interceptor;
    
    import com.alibaba.fastjson.JSONObject;
    import com.auth0.jwt.exceptions.AlgorithmMismatchException;
    import com.auth0.jwt.exceptions.SignatureVerificationException;
    import com.auth0.jwt.exceptions.TokenExpiredException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.util.JSONPObject;
    import com.it2.springbootjwt.util.JWTUtils;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * JWT拦截器
    */
    @Slf4j public class JWTInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Map<String, Object> map = new HashMap<>(); String token = request.getHeader("token"); try { JWTUtils.vertifyToken(token); return true; } 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", "签名算法不匹配"); } catch (Exception e) { e.printStackTrace(); map.put("msg", "token无效"); } map.put("code", false); String jsonString = JSONObject.toJSONString(map); response.setContentType("application/json;charset=UTF-8"); response.getWriter().println(jsonString); return false; } }
    1. 添加拦截器
    package com.it2.springbootjwt.config;
    
    import com.it2.springbootjwt.interceptor.JWTInterceptor;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new JWTInterceptor())
                    .addPathPatterns("/*/*") //其它业务接口
                    .excludePathPatterns("/user/login");//排除不拦截的接口
        }
    }
    
    1. 编写测试业务
    package com.it2.springbootjwt.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @Slf4j
    public class HelloController {
    
    
        @GetMapping("/hello/sayHello")
        public String sayHello() {
            log.info("sayhello....");
            return "success";
        }
    }
    
    1. 启动服务器测试,业务发送请求时,将token添加到header中发送到服务端。这样就能正常执行业务了。
      在这里插入图片描述
      如果不传递token ,或者传递无效的token ,则无法通过拦截器,不能执行业务。
      在这里插入图片描述

    3. 获取用户信息

    显然我们在执行业务时,有时候需要获取用户的信息。那么我们可以通过header中获取。

      @GetMapping("/hello/sayHello")
        public String sayHello(HttpServletRequest request) {
            String token= request.getHeader("token");
            DecodedJWT jwt=JWTUtils.getTokenInfo(token);
    
            System.out.println( jwt.getClaim("username").asString());
            System.out.println( jwt.getClaim("userid").asString());
            log.info("sayhello....");
            return "success";
        }
    

    运行结果
    在这里插入图片描述

  • 相关阅读:
    Java的JDBC编程
    第十章、python字符串操作与with语句及上下文管理器------字符串的操作:字符串的匹配与查找
    可以通过电脑远程控制安卓设备的软件
    Spring事务属性
    探讨 MyBatis 特殊 SQL 执行技巧与注意事项
    Flutter 3.24 和 Dart 3.5 重磅发布
    Macos 远程登录 Ubuntu22.04 桌面
    Linux操作系统之基础IO
    前端面试题 - 元素的innerText outerText innerHTML的区别?
    React造轮子项目工程搭建经历
  • 原文地址:https://blog.csdn.net/u011628753/article/details/126934122