实战SpringBoot集成JWT实现token验证
目录
- 环境搭建
- 1、新建一个SpringBoot项目Jwt-Demo,引入项目后面需要用到的jar包
- 2、数据库结构
- 3、配置文件application.properties
- 4、Entity包下新建一个User类
- 5、Dao包下新建一个UserDao
- 6、Service包下新建一个USerService
- 7、UseService的实现类UserServiceImp
- 8、controller包下新建一个UserController
- 9、在resource文件夹下新建一个Usermapper文件
- 10、JWT工具类JwtUtils
- 引入JWT
- 登录操作
- 验证操作
- 程序优化
- 测试验证
- 总结
由base64加密后的header和payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了JWT字符串
往期介绍了JWT相关概念以及基本操作,接下来介绍如何在SpringBoot中整合JWT实现登陆注册
文章图片
环境搭建
1、新建一个SpringBoot项目Jwt-Demo,引入项目后面需要用到的jar包
org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-testtestorg.mybatis.spring.boot mybatis-spring-boot-starter2.1.3 mysql mysql-connector-java8.0.25 com.alibaba druid1.2.1 org.projectlombok lombok1.18.12 org.mybatis.spring.boot mybatis-spring-boot-starter-test2.1.3 com.auth0 java-jwt3.4.0
2、数据库结构
文章图片
有一个JWT库,里面还有一个User表
3、配置文件application.properties
server.port=8989spring.datasource.type=com.alibaba.druid.pool.DruidDataSourcespring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/JWT?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=truespring.datasource.username=rootspring.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; @Datapublic class User {privateString username; privateString password; privateint id; }
5、Dao包下新建一个UserDao
@Mapperpublic 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; @Servicepublic class UserServiceImpI implements UserService {@Autowiredprivate UserDao userDao; @Overridepublic User login(User user) {User userdb=userDao.login(user); if(userdb!=null){Map map=new HashMap<>(); map.put("name",userdb.getUsername()); return userdb; }thrownew RuntimeException("登录失败"); }}
8、controller包下新建一个UserController
@RestControllerpublic class UserController {@Autowiredprivate UserService userService; @GetMapping("/user/login")public Map login(User user){log.info("用户名:"+user.getUsername()); log.info("密码:"+user.getPassword()); Map 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文件
select *from user where username=#{username} and password=#{password}
10、JWT工具类JwtUtils
/** * JWT工具类 * @author yanglingcong * @date 2021/12/31 11:24 AM */public class JwtUtils {//鉴权 相当于私钥保存在服务器上privatestaticfinal Stringsecret="##@$%@#S#WS"; /*** 生成token* @author yanglingcong* @date 2021/12/31 11:23 AM* @param map* @return String*/public staticString getToken(Map map){Calendar instance=Calendar.getInstance(); //默认七天过期instance.add(Calendar.DATE,7); //创建JWTJWTCreator.Builder builder = JWT.create(); //payloadmap.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*/publicstaticDecodedJWTverify(String token) {returnJWT.require(Algorithm.HMAC256(secret)).build().verify(token); }}
整个项目概览
文章图片
测试验证是否能够连通数据库
【实战SpringBoot集成JWT实现token验证】访问:localhost:8989/user/login?username=ylc&password=123456
文章图片
引入JWT
@Slf4j@RestControllerpublic class UserController {@Autowiredprivate UserService userService; @GetMapping("/user/login")public Map login(User user){log.info("用户名:"+user.getUsername()); log.info("密码:"+user.getPassword()); Map map=new HashMap<>(); try {userService.login(user); map.put("msg","登录成功"); map.put("code","200"); Map 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")publicMap verityToken(String token){Map 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
文章图片
验证操作
访问:http://localhost:8989/test/verity
文章图片
但是我们这样写在实际项目中是不合理的,把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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {HashMap map=new HashMap<>(); //从http请求头获取tokenString 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 */@Configurationpublic class InterceptConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加拦截器registry.addInterceptor(new JwtInterceptor())//拦截的路径 需要进行token验证的路径.addPathPatterns("/test/verity")//放行的路径.excludePathPatterns("/user/login"); }}
登录是不需要拦截的,其他请求如果有需要验证token就放入拦截器的路径
测试验证
在http请求头中放入token,会被拦截器拦截验证token的有效性
文章图片
总结 这就是SpringBoot整合JWT实际项目一个大概的流程,但是细节方面secret(私钥)肯定每个用户都是不一样的,这里给写死了,而且私钥得保存在一个安全的地方。包括payload部分不能存放敏感的密码信息等等,还可以进行优化。
项目代码:https://gitee.com/yanglingcong/jwt-demo
到此这篇关于实战SpringBoot集成JWT实现token验证的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- Activiti(一)SpringBoot2集成Activiti6
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 私有化轻量级持续集成部署方案--03-部署web服务(下)
- 《机器学习实战》高清中文版PDF英文版PDF+源代码下载
- --木木--|--木木-- 第二课作业#翼丰会(每日一淘6+1实战裂变被动引流# 6+1模式)
- Spring集成|Spring集成 Mina
- springboot使用redis缓存
- 2020-07-29《吴军·阅读与写作50讲》24实战才能转化效能
- springboot整合数据库连接池-->druid