springboot整合JWT

有关JWT的详解可上网查资料,其主要就是用来生成token,举个例子,访问接口需要先进行登录认证,认证通过才能进行访问。也就是先通过用户名和密码登录,后台查询是否存在该用户,若存在则生成token返回,当访问其他接口时携带token请求,后台验证token,验证成功则可以访问,验证失败则禁止访问。

下面为使用JWT生成token以及验证token的简单测试代码:

生成token:

 @Test
    public void jwtTest() {
        //设置从现在开始10秒后
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,90);
        //生成令牌
        String token = JWT.create()
                .withClaim("username","张三") //设置自定义用户名
                .withExpiresAt(instance.getTime())  //设置过期时间
                .sign(Algorithm.HMAC256("token*!us%#Eu"));  //设置签名 尽量复杂
        //输出令牌
        System.out.println(token);

运行结果:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Mzc3Mzg0NTksInVzZXJuYW1lIjoi5byg5LiJIn0.yjomlApRc9lVb8CI0Nn6kh5GUCeCHfDQDZOvBn6e31A

验证token:

@Test
    public void JwtVerifyTest() {
        //生成token时所使用的签名
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("token*!us%#Eu")).build();
        //验证生成的token
        DecodedJWT decodedJWT = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2Mzc3Mzg0NTksInVzZXJuYW1lIjoi5byg5LiJIn0.yjomlApRc9lVb8CI0Nn6kh5GUCeCHfDQDZOvBn6e31A");
        System.out.println("用户名:" + decodedJWT.getClaim("username").asString());//存的什么类型取就用什么类型
        System.out.println("过期时间:" + decodedJWT.getExpiresAt());
    }

运行结果:

用户名:张三
过期时间:Wed Nov 24 15:20:59 CST 2021
======================================================================

======================================================================

下面使用Springboot+JWT来实现用户想要访问某些业务接口需要先登录、获取token、验证token,验证通过才可以访问。

工程目录:

pom.xml配置文件:

<?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.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>org.example</groupId>
    <artifactId>java_test</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>

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

        <!--引入mybatis-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!--引入jwt-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.10.3</version>
        </dependency>

        <!--引入mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <!--引入druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>



</project>

resource下的application.properties配置文件:

server.port=8989
server.servlet.context-path=/jwt_demo

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/pcprtest?serverTimezone=Asia/Shanghai&useSSL=true
spring.datasource.username=root
spring.datasource.password=12345

mybatis.type-aliases-package=com.test.entity
mybatis.mapper-locations=classpath:mapper/*.xml

logging.level.com.test.dao=debug

 由于本次针对实现token获取及验证流程,所涉及的代码十分简单,在此省略entity、dao、mapper的代码。

JWT工具类:

package com.test.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

public class JWTUtils {

    private static String TOKEN = "token*!us%#Eu";

    /**
     * 生成token
     * @param map
     * @return
     */
    public static String getToken(Map<String,String> map) {
        JWTCreator.Builder builder = JWT.create();
        //这里采用lambda表达式
        //遍历map,设置负载(payload)
        map.forEach((k,v) -> builder.withClaim(k,v));
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.SECOND,90);
        builder.withExpiresAt(instance.getTime());
        return builder.sign(Algorithm.HMAC256(TOKEN));
    }

    /**
     * 验证token
     * @param token
     */
    public static void verify(String token) {
        JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token);
    }

    /**
     * 获取token中的负载信息(payload)
     * @param token
     * @return
     */
    public static DecodedJWT getTokenInfo(String token) {
        return JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token);
    }
}

UserService接口:

package com.test.service;

import com.test.entity.UserEntity;

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

 UserServiceImpl实现类:

package com.test.service.impl;

import com.test.dao.UserDao;
import com.test.entity.UserEntity;
import com.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public UserEntity login(UserEntity user) {
        //根据接收的用户名和密码查询数据库
        UserEntity userEntity = userDao.login(user);
        if (userEntity != null) {
            return userEntity;
        }
        throw new RuntimeException("登录失败--");
    }
}

ControllerTest类:

package com.test.controller;

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.test.entity.UserEntity;
import com.test.service.UserService;
import com.test.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@PostMapping("/user")
@Slf4j
public class ControllerTest {

    @Autowired
    UserService userService;

    @RequestMapping("/login")
    public Map<String,Object> login(@RequestBody UserEntity user) {
        Map<String,Object> result = new HashMap<>();
        log.info("用户名:[{}]",user.getUsername());
        log.info("密码:[{}]",user.getPassword());
        try {
            UserEntity userEntity = userService.login(user);
            Map<String,String> payloadMap = new HashMap<>();
            payloadMap.put("id",userEntity.getId().toString());
            payloadMap.put("username",userEntity.getUsername());
            String token = JWTUtils.getToken(payloadMap);
            result.put("state",true);
            result.put("msg","登陆成功~");
            result.put("token",token);
        } catch (Exception e) {
            result.put("state",false);
            result.put("msg",e.getMessage());
        }
        return result;
    }

    @PostMapping("/verify")
    public Map<String,Object> verify(@RequestParam("token") String token) {
        Map<String,Object> map = new HashMap<>();
        try {
            JWTUtils.verify(token);
            map.put("state",true);
            map.put("msg","验证通过~~");
        } catch (TokenExpiredException e) {
            map.put("state",false);
            map.put("msg","token已过期!");
        } catch (SignatureVerificationException e) {
            map.put("state",false);
            map.put("msg","签名错误!");
        } catch (AlgorithmMismatchException e) {
            map.put("state",false);
            map.put("msg","算法不匹配!");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("state",false);
            map.put("msg","无效token!");
        }
        return map;
    }

}

Postman调用登录接口进行测试:

输入错误的用户名和密码:

输入正确的用户名和密码:

下面来测试token验证接口:

token过期

错误的token

有效的token

 那么又有问题了,如果这么设计,每个接口都需要加上token验证流程,产生代码冗余。因此我们采用拦截器来实现需求。

 自定义拦截器JWTInterceptor类:

package com.test.interceptor;

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.test.utils.JWTUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

public class JWTIntercepter 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 {
            JWTUtils.verify(token);
            map.put("state",true);
            map.put("msg","验证通过~~");
            return true;
        } catch (TokenExpiredException e) {
            map.put("state",false);
            map.put("msg","token已过期!");
        } catch (SignatureVerificationException e) {
            map.put("state",false);
            map.put("msg","签名错误!");
        } catch (AlgorithmMismatchException e) {
            map.put("state",false);
            map.put("msg","算法不匹配!");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("state",false);
            map.put("msg","无效token!");
        }
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

 

 拦截器配置类InterceptorConfig:

package com.test.config;

import com.test.interceptor.JWTIntercepter;
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 JWTIntercepter())
                .excludePathPatterns("/user/**")    //  放行/User/**的请求路径
                .addPathPatterns("/**"); //  拦截除了/user/**的所有请求路径
    }
}

添加其他的业务Controller类:

package com.test.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/business")
public class BusinessController {

    @RequestMapping("/test1")
    public Map<String,Object> businessOne() {
        Map<String,Object> map = new HashMap<>();
        map.put("msg","业务接口1");
        map.put("state",true);
        return map;
    }
    @RequestMapping("/test2")
    public Map<String,Object> businessTwo() {
        Map<String,Object> map = new HashMap<>();
        map.put("msg","业务接口2");
        map.put("state",true);
        return map;
    }
    @RequestMapping("/test3")
    public Map<String,Object> businessThree() {
        Map<String,Object> map = new HashMap<>();
        map.put("msg","业务接口3");
        map.put("state",true);
        return map;
    }
}

 

下面来进行测试:

不登录直接调用业务接口

登录后获取token,之后将token放入请求头中调用业务接口

 至此,Springboot+JWT实现token获取验证的流程就实现了~~~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程简介:历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值