• Springboot整合JWT


    一、Springboot整合JWT

    强烈建议小伙伴们阅读 JWT 基础概念https://www.cnblogs.com/code-duck/p/13479792.html
    再进行Springboot整合

    1.创建Springboot项目

    2.配置pom信息

    <!--?xml version="1.0" encoding="UTF-8"?-->
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelversion>4.0.0</modelversion>
    
        <parent>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-parent</artifactid>
            <version>2.3.1.RELEASE</version>
            <relativepath>
        </relativepath></parent>
    
        <groupid>com.duck.code</groupid>
        <artifactid>Springboot-JWT</artifactid>
        <version>1.0-SNAPSHOT</version>
        
        <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.4.0</version>
            </dependency>
    
            <dependency>
                <groupid>org.projectlombok</groupid>
                <artifactid>lombok</artifactid>
                <optional>true</optional>
            </dependency>
    
            <!--mybatis plus-->
            <dependency>
                <groupid>com.baomidou</groupid>
                <artifactid>mybatis-plus-boot-starter</artifactid>
                <version>3.3.2</version>
            </dependency>
    
            <!--代码生成器-->
            <dependency>
                <groupid>com.baomidou</groupid>
                <artifactid>mybatis-plus-generator</artifactid>
                <version>3.3.2</version>
            </dependency>
    
            <!--逆向工程需要模板引擎-->
            <dependency>
                <groupid>org.freemarker</groupid>
                <artifactid>freemarker</artifactid>
                <version>2.3.30</version>
            </dependency>
    
            <!--mysql依赖-->
            <dependency>
                <groupid>mysql</groupid>
                <artifactid>mysql-connector-java</artifactid>
                <scope>runtime</scope>
            </dependency>
    
            <!--连接池-->
            <dependency>
                <groupid>com.alibaba</groupid>
                <artifactid>druid</artifactid>
                <version>1.1.20</version>
            </dependency>
        </dependencies>
    </project>
    

    3.配置application配置文件信息

    server:
      port: 8081
    spring:
      datasource:
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_jwt?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
        type: com.alibaba.druid.pool.DruidDataSource
    
    mybatis-plus:
      global-config:
        db-config:
          table-prefix: tb_   # 表明前缀
      type-aliases-package: com.code.duck.entity  # 实体类所在包
      mapper-locations: classpath*:/mapper/**Mapper.xml   # xml文件所在位置
    

    5.Springboot主启动类配置

    @SpringBootApplication
    @MapperScan("com.duck.code.mapper")
    public class JWTApplication {
        public static void main(String[] args) {
            SpringApplication.run(JWTApplication.class,args);
        }
    }
    

    4.Springboot整合MybatisPlus

    ​ 使用MybatisPlus代码生成器,生成entity、controller、service,service.impl、mapper、xml文件

    代码生成器参考本人:Springboot整合MybatisPlus的文章 https://www.cnblogs.com/code-duck/p/13481550.html

    6.封装JWT工具类

    JWTUtil工具类主要用于生成JWT令牌(token)、核实token信息、对token进行解密

    JWT抽象类

    JWT抽象类中的三个方法,对应于上述三个功能

    public abstract class JWT {
    
        /**
         * Decode a given Json Web Token.
         *
         * @param token with jwt format as string.
         * @return a decoded JWT.
         */
        public static DecodedJWT decode(String token) throws JWTDecodeException {
            return new JWTDecoder(token);
        }
    
        /**
         * Returns a {@link JWTVerifier} builder with the algorithm to be used to validate token signature.
         *
         * @param algorithm that will be used to verify the token's signature.
         * @return {@link JWTVerifier} builder
         * @throws IllegalArgumentException if the provided algorithm is null.
         */
        public static Verification require(Algorithm algorithm) {
            return JWTVerifier.init(algorithm);
        }
    
        /**
         * Returns a Json Web Token builder used to create and sign tokens
         *
         * @return a token builder.
         */
        public static JWTCreator.Builder create() {
            return JWTCreator.init();
        }
    }
    

    JWTUtil工具类

    public class JWTUtil {
    
        // 用于JWT进行签名加密的秘钥
        private static String SECRET = "code-duck-*%#@*!&";
    
        /**
         * @Param: 传入需要设置的payload信息
         * @return: 返回token
         */
        public static String generateToken(Map<string, string=""> map) {
            JWTCreator.Builder builder = JWT.create();
    
            // 将map内的信息传入JWT的payload中
            map.forEach((k, v) -> {
                builder.withClaim(k, v);
            });
    
            // 设置JWT令牌的过期时间为60
            Calendar instance = Calendar.getInstance();
            instance.add(Calendar.SECOND, 60);
            builder.withExpiresAt(instance.getTime());
    
            // 设置签名并返回token
            return builder.sign(Algorithm.HMAC256(SECRET)).toString();
        }
    
        /**
         * @Param: 传入token
         * @return:
         */
        public static void verify(String token) {
            JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        }
    
        /**
         * @Param: 传入token
         * @return: 解密的token信息
         */
        public static DecodedJWT getTokenInfo(String token) {
            return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);
        }
    }
    

    7.UserController控制器中声明登录接口

    @RestController
    @Slf4j
    public class UserController {
    
        @Resource
        private UserService userService;
    
        @PostMapping(value = "/user/login")
        public Map<string, string=""> userLogin(@RequestBody User user) {
            log.info(user.getUsername());
            log.info(user.getPassword());
    
            QueryWrapper<user> wrapper = new QueryWrapper<>();
    
            wrapper.eq("username", user.getUsername());
            wrapper.eq("password",user.getPassword());
            // 数据库中查询用户信息
            User one = userService.getOne(wrapper);
    
            HashMap<string, string=""> result = new HashMap<>(); // 返回结果信息给前端
    
            if (one == null){
                result.put("code","401");
                result.put("msg","用户名或密码错误");
            }
    
            Map<string, string=""> map = new HashMap<>(); //用来存放payload信息
    
            map.put("id",one.getId().toString());
            map.put("username",one.getUsername());
            map.put("role",one.getRole());
    
            // 生成token令牌
            String token = JWTUtil.generateToken(map);
    
            // 返回前端token
            result.put("code","200");
            result.put("msg","登录成功");
            result.put("token",token);
            return result;
        }
    }
    

    8.启动Springboot

    使用postman进行接口测试,查看是否返回了正确响应,并生成了token令牌

    image-20200811205734830

    二、为Springboot配置拦截器

    • 当用户登录成功时,服务端为该用户生成了一个时长为60的token令牌,"token": "xxx.xxx.xx"的形式 以返回给前端系统
    • 当前端在每次请求时,我们选择将token令牌放至放入HTTP Header中的Authorization位
    • 服务器对所有的请求进行拦截并校验token(除登录接口外)。如果token 信息不正确或过时,则向前端返回错误代码,校验正确则放行。

    创建JWT拦截器

    在此处进行token校验,如果校验成功则放行,否则返回异常信息给前端系统

    public class JWTInterceptor implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            Map<string, string=""> map = new HashMap<>();
    
            //获取请求头中的token令牌
            String token = request.getHeader("token");
            try {
                JWTUtil.verify(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", "token算法不一致!");
            } catch (Exception e) {
                e.printStackTrace();
                map.put("msg", "token无效!!");
            }
            map.put("code", "403");//设置状态
            //将 map 转为json  jackson
            String json = new ObjectMapper().writeValueAsString(map);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().println(json);
            return false;
        }
    }
    

    配置WebMvcConfigurer拦截器

    在此处配置过滤规则:即添加JWTInterceptor token校验拦截器、拦截非登录接口外的一切/user接口

    @Configuration
    public class MyWebMvcConfigurer implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new JWTInterceptor())
                    .excludePathPatterns("/user/login") // 登录接口不用于token验证
                    .addPathPatterns("/user/**"); // 其他非登录接口都需要进行token验证
        }
    }
    

    在控制器中添加测试接口

    @GetMapping(value = "/user/test")
    public Map<string,string> test(HttpServletRequest request){
        
        Map<string, string=""> map = new HashMap<>();
        //处理自己业务逻辑
        String token = request.getHeader("token");
        DecodedJWT claims = JWTUtil.getTokenInfo(token);
        log.info("用户id: [{}]",claims.getClaim("id").asString());
        log.info("用户name: [{}]",claims.getClaim("username").asString());
        log.info("用户role: [{}]",claims.getClaim("role").asString());
        map.put("code","200");
        map.put("msg","请求成功!");
        return map;
    }
    

    启动Springboot进行测试

    1. 访问http://localhost:8081/user/login进行登录测试,获取服务器端返回的token信息
    2. 测试http://localhost:8081/user/test,在其请求头配置token信息

    image-20200811211951236</string,></string,string></string,></string,></string,></string,></string,>

  • 相关阅读:
    Redis详解----- 缓存穿透、缓存击穿、缓存雪崩
    mysql存储时间
    MAT入门到精通
    meven依赖思考记录
    线程池原理
    vscode + wsl2
    java架构师学习路线-高级
    java架构师学习路线-初级
    (二)垃圾回收
    (一)内存区域
  • 原文地址:https://www.cnblogs.com/code-duck/p/13485236.html
Copyright © 2020-2023  润新知