欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

实战SpringBoot集成JWT实现token验证

程序员文章站 2022-04-10 09:57:30
目录环境搭建1、新建一个springboot项目jwt-demo,引入项目后面需要用到的jar包2、数据库结构3、配置文件application.properties4、entity包下新建一个use...

jwt可以理解为一个加密的字符串,里面由三部分组成:头部(header)、负载(payload)、签名(signature)

由base64加密后的header和payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt字符串

往期介绍了jwt相关概念以及基本操作,接下来介绍如何在springboot中整合jwt实现登陆注册

实战SpringBoot集成JWT实现token验证

环境搭建

1、新建一个springboot项目jwt-demo,引入项目后面需要用到的jar包

  <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>
        <!--引入mybatis-->
        <dependency>
            <groupid>org.mybatis.spring.boot</groupid>
            <artifactid>mybatis-spring-boot-starter</artifactid>
            <version>2.1.3</version>
        </dependency>
        <!--引入mysql-->
        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <version>8.0.25</version>
        </dependency>
        <!--引入druid数据库连接池-->
        <dependency>
            <groupid>com.alibaba</groupid>
            <artifactid>druid</artifactid>
            <version>1.2.1</version>
        </dependency>
        <!--引入lombok-->
        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupid>org.mybatis.spring.boot</groupid>
            <artifactid>mybatis-spring-boot-starter-test</artifactid>
            <version>2.1.3</version>
        </dependency>
        <!--引入jwt-->
        <dependency>
            <groupid>com.auth0</groupid>
            <artifactid>java-jwt</artifactid>
            <version>3.4.0</version>
        </dependency>
    </dependencies>

2、数据库结构

实战SpringBoot集成JWT实现token验证

有一个jwt库,里面还有一个user表

3、配置文件application.properties

server.port=8989

spring.datasource.type=com.alibaba.druid.pool.druiddatasource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.driver
spring.datasource.url=jdbc:mysql://localhost:3306/jwt?characterencoding=utf8&usessl=false&servertimezone=utc&rewritebatchedstatements=true
spring.datasource.username=root
spring.datasource.password=12345678

#mybatis扫描的包
mybatis.type-aliases-package=com.ylc
#mapper文件路径
mybatis.mapper-locations=classpath:/**/*.xml

#开启sql打印日志  logging.level后面是mybatis对应的方法接口所在的包
logging.level.com.ylc.jwtdemo.dao=debug

4、entity包下新建一个user类

import lombok.data;

@data
public class user {
    private  string username;
    private  string password;
    private  int id;
}

5、dao包下新建一个userdao

@mapper
public interface userdao {

    user login(user user);
}

6、service包下新建一个userservice

public interface userservice {
    user login(user user);//登录接口
}

7、useservice的实现类userserviceimp

import java.util.hashmap;
import java.util.map;

@service
public class userserviceimpi implements userservice {

    @autowired
    private userdao userdao;

    @override
    public user login(user user) {
        user userdb=userdao.login(user);
        if(userdb!=null)
        {
            map<string,string> map=new hashmap<>();
            map.put("name",userdb.getusername());
            return userdb;
        }
        throw  new runtimeexception("登录失败");
    }
}

8、controller包下新建一个usercontroller

@restcontroller
public class usercontroller {

    @autowired
    private userservice userservice;

    @getmapping("/user/login")
    public map<string,object> login(user user)
    {
        log.info("用户名:"+user.getusername());
        log.info("密码:"+user.getpassword());
        map<string,object> map=new hashmap<>();
        try {
            userservice.login(user);
            map.put("msg","登录成功");
            map.put("code","200");
        }
        catch (exception ex)
        {
            map.put("msg","登录失败");
        }

        return map;
    }
}

9、在resource文件夹下新建一个usermapper文件

<?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">
<!--namespace 指的是要配置的全限定类名-->
<mapper namespace="com.ylc.jwtdemo.dao.userdao">
    <select id="login" parametertype="com.ylc.jwtdemo.entity.user" resulttype="com.ylc.jwtdemo.entity.user">
        select *from user where username=#{username} and password=#{password}
    </select>
</mapper>

10、jwt工具类jwtutils

/**
 * jwt工具类
 * @author yanglingcong
 * @date 2021/12/31 11:24 am
 */
public class jwtutils {
    //鉴权 相当于私钥保存在服务器上
    private  static  final string  secret="##@$%@#s#ws";


    /**
     * 生成token
     * @author yanglingcong
     * @date 2021/12/31 11:23 am
     * @param map
     * @return string
     */
    public static  string gettoken(map<string,string> map)
    {
        calendar instance=calendar.getinstance();
        //默认七天过期
        instance.add(calendar.date,7);
        //创建jwt
        jwtcreator.builder builder = jwt.create();

        //payload
        map.foreach((k,v)->{
            builder.withclaim(k,v);
        });
        //指定令牌过期时间
        builder.withexpiresat(instance.gettime());

        string token=builder.sign(algorithm.hmac256(secret));
        return token;
    }

    /**
     * 验证token
     * @author yanglingcong
     * @date 2021/12/31 11:26 am
     * @param token
     */
    public  static  decodedjwt  verify(string token) {
        return  jwt.require(algorithm.hmac256(secret)).build().verify(token);
    }

}

整个项目概览

实战SpringBoot集成JWT实现token验证

测试验证是否能够连通数据库

访问:localhost:8989/user/login?username=ylc&password=123456

实战SpringBoot集成JWT实现token验证

引入jwt

@slf4j
@restcontroller
public class usercontroller {

    @autowired
    private userservice userservice;

    @getmapping("/user/login")
    public map<string,object> login(user user)
    {
        log.info("用户名:"+user.getusername());
        log.info("密码:"+user.getpassword());
        map<string,object> map=new hashmap<>();
        try {
            userservice.login(user);
            map.put("msg","登录成功");
            map.put("code","200");

            map<string,string> payload=new hashmap<>();
            payload.put("name",user.getusername());
            string token= jwtutils.gettoken(payload);
            map.put("token",token);
        }
        catch (exception ex)
        {
            map.put("msg","登录失败");
        }

        return map;
    }

    @postmapping("/test/verity")
    public  map<string,string> veritytoken(string token)
    {
        map<string, string> map=new hashmap<>();
        log.info("token为"+token);
        try {
            decodedjwt verify = jwtutils.verify(token);
            map.put("msg","验证成功");
            map.put("state","true");
        }
        catch (exception exception)
        {
            map.put("msg","验证失败");
            exception.printstacktrace();
        }
        return map;
    }
}

登录操作

访问:http://localhost:8989/user/login?username=ylc&password=123456

实战SpringBoot集成JWT实现token验证

验证操作

访问:http://localhost:8989/test/verity

实战SpringBoot集成JWT实现token验证

但是我们这样写在实际项目中是不合理的,把token生成的代码放在了controller中,业务逻辑是不能放在controller层中的。假如很多接口都需要token来进行验证保护,那每一个接口都需要添加这样一段代码,造成代码冗余。

程序优化

如果是web项目使用拦截器进行优化,如果是springcloud项目在网关层进行拦截,下面演示如何使用拦截器拦截

最好还把jwt生成token放在http请求头,这样就不需要把token当成参数传递了

新建一个拦截器jwtinterceptor

/**
 * jwt拦截器
 * @author yanglingcong
 * @date 2021/12/31 12:39 pm
 */
public class jwtinterceptor implements handlerinterceptor {
    @override
    public boolean prehandle(httpservletrequest request, httpservletresponse response, object handler) throws exception {
        hashmap<string, string> map=new hashmap<>();
        //从http请求头获取token
        string token = request.getheader("token");
        try {
            //如果验证成功放行请求
            decodedjwt verify = jwtutils.verify(token);
            return true;
        }
        catch (exception exception)
        {
            map.put("msg","验证失败:"+exception);
        }
        string json = new objectmapper().writevalueasstring(map);
        response.setcontenttype("application/json:charset=utf=8");
        response.getwriter().println(json);
        return false;
    }
}

然后把拦截器注册到过滤器中,新建一个过滤器interceptconfig

/**
 * @author yanglingcong
 */
@configuration
public class interceptconfig implements webmvcconfigurer {
    @override
    public void addinterceptors(interceptorregistry registry) {
        //添加拦截器
        registry.addinterceptor(new jwtinterceptor())
                //拦截的路径 需要进行token验证的路径
                .addpathpatterns("/test/verity")
                //放行的路径
                .excludepathpatterns("/user/login");
    }
}

登录是不需要拦截的,其他请求如果有需要验证token就放入拦截器的路径

测试验证

在http请求头中放入token,会被拦截器拦截验证token的有效性

实战SpringBoot集成JWT实现token验证

总结

这就是springboot整合jwt实际项目一个大概的流程,但是细节方面secret(私钥)肯定每个用户都是不一样的,这里给写死了,而且私钥得保存在一个安全的地方。包括payload部分不能存放敏感的密码信息等等,还可以进行优化。

项目代码:https://gitee.com/yanglingcong/jwt-demo

到此这篇关于实战springboot集成jwt实现token验证的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。