Loading

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,>

posted @ 2020-08-11 21:21  codeduck  阅读(2818)  评论(1编辑  收藏  举报