springboot entity date_SpringBoot+JWT实战(附源码)

SpringBoot集成JWT

首先我们搭建好SpringBoot框架,SpringBoot环境准备就绪。接下来执行以下操作:

1.引入依赖

引入JWT依赖,由于是基于Java,所以需要的是java-jwt

<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.5.0</version>
</dependency>

2.自定义注解

在这一步,我们在annotation包下定义一个用户需要登录才能进行其他接口访问等一系列操作的注解TokenRequired

`@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequired {boolean required() default true;
}

@Target旨意为我们自定义注解@TokenRequired的作用目标,因为我们本次注解的作用目标为方法层级,因此使用 ElementType.METHOD

@Retention旨意为我们自定义注解 @TokenRequired的保留位置,@TokenRequired的保留位置被定义为RetentionPolicy.RUNTIME这种类型的注解将被JVM保留,他能在运行时被JVM或其他使用反射机制的代码所读取和使用。

3.定义实体类

在entity包中,我们使用lombok,简单自定义一个实体类User。

`@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {String Id;String username;String password;
}

4.定义一个JWT工具类

在这一步,我们在util包下面创建一个JwtUtil工具类,用于生成token和校验token。

`public class JwtUtil {//过期时间15分钟private static final long EXPIRE_TIME = 15*60*1000;//生成签名,15分钟后过期public static String sign(String username,String userId,String password){//过期时间Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);//使用用户密码作为私钥进行加密Algorithm algorithm = Algorithm.HMAC256(password);//设置头信息HashMap<String, Object> header = new HashMap<>(2);header.put("typ", "JWT");header.put("alg", "HS256");//附带username和userID生成签名return JWT.create().withHeader(header).withClaim("userId",userId).withClaim("username",username).withExpiresAt(date).sign(algorithm);}//校验tokenpublic static boolean verity(String token,String password){try {Algorithm algorithm = Algorithm.HMAC256(password);JWTVerifier verifier = JWT.require(algorithm).build();verifier.verify(token);return true;} catch (IllegalArgumentException e) {return false;} catch (JWTVerificationException e) {return false;}}
}

5.业务校验并生成token

在service包下,我们创建一个UserService,并定义一个login方法,用于做登录接口的业务层数据校验,并调取JwtUtil中方法生成token。

`@Service("UserService")
public class UserService {@AutowiredUserMapper userMapper;public String login(String name, String password) {String token = null;try {//校验用户是否存在User user = userMapper.findByUsername(name);if(user == null){ResultDTO.failure(new ResultError(UserError.EMP_IS_NULL_EXIT));}else{//检验用户密码是否正确if(!user.getPassword().equals(password)){ResultDTO.failure(new ResultError(UserError.PASSWORD_OR_NAME_IS_ERROR));}else {// 生成token,将 user id 、userName保存到 token 里面token = JwtUtil.sign(user.getUsername(),user.getId(),user.getPassword());}}} catch (Exception e) {e.printStackTrace();}return token;}
}

Algorithm.HMAC256():使用HS256生成token,密钥则是用户的密码,唯一密钥的话可以保存在服务端。withAudience()存入需要保存在token的信息,这里我把用户ID存入token中。

6.定义拦截器

接下来我们需要写一个拦截器去获取token并验证token。

 `public class AuthenticationInterceptor implements HandlerInterceptor {@AutowiredUserService userService;@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {// 从 http 请求头中取出 tokenString token = httpServletRequest.getHeader("token");// 如果不是映射到方法直接通过if(!(object instanceof HandlerMethod)){return true;}HandlerMethod handlerMethod=(HandlerMethod)object;Method method=handlerMethod.getMethod();//检查有没有需要用户权限的注解if (method.isAnnotationPresent(TokenRequired.class)) {TokenRequired userLoginToken = method.getAnnotation(TokenRequired.class);if (userLoginToken.required()) {// 执行认证if (token == null) {throw new RuntimeException("无token,请重新登录");}// 获取 token 中的 user idString userId;try {userId = JWT.decode(token).getClaim("userId").asString();} catch (JWTDecodeException j) {throw new RuntimeException("401");}User user = userService.findUserById(userId);if (user == null) {throw new RuntimeException("用户不存在,请重新登录");}// 验证 tokentry {if(!JwtUtil.verity(token,user.getPassword())){throw new RuntimeException("无效的令牌");}} catch (JWTVerificationException e) {throw new RuntimeException("401");}return true;}}return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
}

AuthenticationInterceptor拦截器实现了HandlerInterceptor接口的三个方法:

  1. boolean preHandle ():

预处理回调方法,实现处理器的预处理,第三个参数为响应的处理器,自定义Controller返回值,返回值为true会调用下一个拦截器或处理器,或者接着执行postHandle()和afterCompletion();false表示流程中断,不会继续调用其他的拦截器或处理器,中断执行。

2.void postHandle():

后处理回调方法,实现处理器的后处理(DispatcherServlet进行视图返回渲染之前进行调用),此时我们可以通过modelAndView对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

3.void afterCompletion():

整个请求处理完毕回调方法,该方法也是需要当前对应的Interceptor的preHandle()的返回值为true时才会执行,也就是在DispatcherServlet渲染了对应的视图之后执行。用于进行资源清理。

该拦截器的执行流程为:

  1. 从 http 请求头中取出 token;
  2. 检查有没有需要用户权限的注解,如果需要,检验token是否为空;
  3. 如果token不为空,查询用户信息并校验token;
  4. 校验通过,则进行业务访问处理,校验失败则返回token失效信息。

7.配置拦截器

在配置类上添加了注解@Configuration,标明了该类是一个配置类并且会将该类作为一个SpringBean添加到IOC容器内。

`@Configuration
public class InterceptorConfig implements WebMvcConfigurer {@Beanpublic AuthenticationInterceptor authenticationInterceptor() {return new AuthenticationInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 将我们上步定义的实现了HandlerInterceptor接口的拦截器实例authenticationInterceptor添加InterceptorRegistration中,并设置过滤规则,所有请求都要经过authenticationInterceptor拦截。registry.addInterceptor(authenticationInterceptor()).addPathPatterns("/**");}
}

WebMvcConfigurer接口是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件来实现基本的配置需要。

InterceptorConfig内的addInterceptor需要一个实现HandlerInterceptor接口的拦截器实例,addPathPatterns方法用于设置拦截器的过滤路径规则。

addInterceptors方法中,我们将第6步定义的实现了HandlerInterceptor接口的拦截器实例authenticationInterceptor,添加至InterceptorRegistration中,并设置过滤路径。现在,我们所有请求都要经过authenticationInterceptor的拦截,拦截器authenticationInterceptor通过preHandle方法的业务过滤,判断是否有@TokenRequired 来决定是否需要登录。

8.定义接口方法并添加注解

`@RestController
@RequestMapping("user")
public class UserController {@AutowiredUserService userService;/*** 用户登录* @param user* @return*/@PostMapping("/login")public ResultDTO login( User user){String token = userService.login(user.getUsername(), user.getPassword());if (token == null) {return ResultDTO.failure(new ResultError(UserError.PASSWORD_OR_NAME_IS_ERROR));}Map<String, String> tokenMap = new HashMap<>();tokenMap.put("token", token);return ResultDTO.success(tokenMap);}@TokenRequired@GetMapping("/hello")public String getMessage(){return "你好哇,我是小码仔";}
}
不加注解的话默认不验证,登录接口一般是不验证的。所以我在getMessage()中加上了登录注解,说明该接口必须登录获取token后,在请求头中加上token并通过验证才可以访问。

请求验证

我在代码中对getMessage()添加了@TokenRequired注解,此刻访问该方法时必须要通过登录拿取到token值,并在请求头中添加token才可以访问。我们现在做以下校验:

  1. 直接访问,不在请求头里添加token:

01f1bbc63dd2f02706a83c2a616b7102.png

如上图所示,请求结果显示:无token,请重新登录

2.访问登录接口,获取token,并在请求头中添加token信息:

f870351248c4932ebec7857fd6fddb09.png


此时,访问成功

3.15分钟后,token失效,我们再次在请求头中添加token信息访问:

53c44de724d8ca928d79f1c26b88e36f.png
此时token已失效,返回:无效的令牌。 

总结

回顾一下本次JWT使用的基本业务判断流程:

  1. 用户访问页面,前端请求相关接口,经过拦截器,拦截器中从 http 请求头中取出 token;
  2. 检查该接口有没有@TokenRequired注解,如果没有,直接放行;如果有,检验token是否为空;
  3. 如果token为空,访问失败;token不为空,则查询用户信息并校验token;
  4. 校验通过,则进行业务访问处理,校验失败则返回token失效信息。

不足之处:本次集成只是做一个简单的JWT使用介绍,没有实现token的过期刷新机制,此种情况下用户每隔15分钟就需要重新登录一次,如果在实际生产环境中使用,可能会被用户打死,因此实际开发中并不推荐。

关于token的刷新机制,将在下篇文章中为大家解读并附上源码。

本次集成代码地址:https://github.com/bailele1995/springboot-jjwt.git
来源:https://juejin.im/post/5ea27c5be51d4546c27bdf94?utm_source=tuicool&utm_medium=referral

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

六、springboot(三)配置双数据源

1、目录结构 2.jdbc.properties配置 #db hougespring.datasource.houge.jdbc-urljdbc:oracle:thin:192.168.0.120:1521:ORCLspring.datasource.houge.usernamehougespring.datasource.houge.passwordmonkeyspring.datasource.houge.driver-class-nameoracle.jdbc.driver.Oracle…

在您的构建过程中添加微基准测试

介绍 作为一个行业&#xff0c;我们正在采用更高的透明度和更可预测的构建过程&#xff0c;以减少构建软件的风险。 持续交付的核心原则之一是通过反馈循环收集反馈。 在Dev9中 &#xff0c;我们采用了与CD原则相一致的“ 先知道 ”原则&#xff0c;这意味着我们&#xff08;开…

【C/C++】Linux下使用system()函数一定要谨慎

曾经的曾经&#xff0c;被system()函数折磨过&#xff0c;之所以这样&#xff0c;是因为对system()函数了解不够深入。只是简单的知道用这个函数执行一个系统命令&#xff0c;这远远不够&#xff0c;它的返回值、它所执行命令的返回值以及命令执行失败原因如何定位&#xff0c;…

定时器和多线程的不同

最近在做项目的时候&#xff0c;遇到了视频采集图像时。使用定时器与或使用多线程有些纠结。原先用了定时器测试了&#xff0c;因为项目需要占用较多的cpu&#xff0c;所以很明显图像显示比较卡。 所以网上查了下。贴出来大家学习学习。 软件定时器和多线程在控制工程中有着非…

华为s8600手机驱动_只有手机才能快充?华为MateBook X的灵巧快充解放你的续航焦虑-华为 ——快科技(驱动之家旗下媒体)-...

充电&#xff0c;永远是数码科技圈必不可少的话题。然而&#xff0c;想要好好给设备充电太并不容易。每次外出&#xff0c;为了防止手机没电&#xff0c;大家的兜里必然要揣着一个大容量的充电宝才安心&#xff0c;这也是手机快充最初诞生的原因。快充技术指的是通过技术手段&a…

linux系统编程之进程(七):system()函数使用

一&#xff0c;system()理解 功能&#xff1a;system()函数调用“/bin/sh -c command”执行特定的命令&#xff0c;阻塞当前进程直到command命令执行完毕 原型&#xff1a; int system(const char *command); 返回值&#xff1a; 如果无法启动shell运行命令&#xff0c;system将…

Scrapy安装介绍

Scrapy安装介绍 一、 Scrapy简介 Scrapy is a fast high-level screen scraping and web crawling framework, used to crawl websites and extract structured data from their pages. It can be used for a wide range of purposes, from data mining to monitoring and aut…

数据库常用语句整理

数据库常用语句整理 --查询 select * from emp;--oracle 分页 SELECT * FROM (SELECT rownum AS rnum, e.*FROM emp eWHERE rownum < 10 ) WHERE rnum > 5;--复制表 CREATE TABLE new_table AS SELECT * FROM old_table; 参考资料 https://www.techonthenet.com/sql/tabl…

c语言n次方怎么输入_C语言实现斐波拉契数列

C语言实现斐波拉契数列教程怎么使用 C 语言实现计算斐波拉契数列的第 N 项的值&#xff1f;C语言实现斐波拉契数列详解背景知识斐波那契数列是一组第一位和第二位为 1&#xff0c;从第三位开始&#xff0c;后一位是前两位和的一组递增数列&#xff0c;像这样的&#xff1a;1、1…

junit 测试mvc_Spring MVC控制器JUnit测试

junit 测试mvcJUnit测试Spring MVC控制器并非易事 。 但是最近&#xff0c;一个新项目 &#xff08;即将在Spring推出&#xff09;提供了新的工具来简化此工作。 这篇文章说明了如何通过JUnit测试来测试一个简单的控制器。 该代码是JUnit Testing Spring Service和DAO&#xff…

python中if __name__ == '__main__': 的解析

当你打开一个.py文件时,经常会在代码的最下面看到if __name__ __main__:,现在就来介 绍一下它的作用. 模块是对象&#xff0c;并且所有的模块都有一个内置属性 __name__。一个模块的 __name__ 的值取决于您如何应用模块。如果 import 一个模块&#xff0c;那么模块__name__ 的…

LuoguP1268树的重量【构造/思维】By cellur925

题目传送门 Description 给你一个矩阵$M$&#xff0c;$M(i,j)$表示$i$到$j$的最短距离。定义树的重量为树上各边权之和&#xff0c;对于任意给出的合法矩阵$M$&#xff0c;已知它所能表示树的重量是唯一确定的。给出一个矩阵&#xff0c;求它所表示的树的重量。 Sol 这道题我想…

pydev插件安装方法

eclipse 版本&#xff1a; PYDEV:附件在本博客资源下载 下载附件后解压缩,将features和plugins个目录复制粘贴到eclipse相对应的目录下面&#xff0c;然后在启动Eclipse&#xff0c;在Help&#xff0d;》check for UPdates&#xff0c;然后弹出的界面即可看到pydev的插件。 …

将速度加快到自己的个人代码生成器中

Speedment是一个开放源代码工具箱 &#xff0c;可用于生成Java实体和管理器以与数据库进行通信。 如果您需要域模型的对象关系映射&#xff0c;那么这很好&#xff0c;但是在某些情况下&#xff0c;您可能希望使用数据库作为模板来生成完全不同的东西。 在本文中&#xff0c;我…

python3常用模块_Python3 常用模块1

os模块 通过os模块我们可以与操作系统交互, 控制文件和文件夹 对文件夹操作 # 判断是否为文件夹 os.path.isdir() # 创建文件夹 os.mkdir() # 删除文件夹 os.rmdir() # 列出文件夹内所有文件(返回列表) os.listdir() # 当前文件所在文件夹路径 os.getcwd() # 所在文件夹的路径 …

matlab求最短路径代码_【高等数学】复数,通往真理的最短路径

看图学数学&#xff01;可能是中国最好的高等数学的基础概念讲解&#xff0c;深入浅出、形象生动。没有高深的数学符号&#xff0c;只有你能懂的数学内容。在实数域中&#xff0c;连接两个真理的最短的路径是通过复数域----雅克阿达马现代数学家对复数的看法如斯&#xff0c;无…

怎么解决python Non-ASCII character错误

第一次接触Python&#xff0c;今天刚在Eclipse上安装完PyDev插件准备开始编程&#xff0c;用用简单例子进行调试竟然出现这样的错误&#xff0c; SyntaxError: Non-ASCII character \xef in file C:\Users\Administrator.NUY67O2SLHT6KM0\workspace\Hello World\scr\Hello.py …

Win7下VS2008破解方法

在Win7系统下&#xff0c;无法像xp下通过“控制面板”卸载的方法重新输入序列号来破解VS2008。 但可以通过以下几个步骤来破解&#xff1a; 1.首先需要安装VS2008&#xff0c;可以安装VS2008专业版90天试用版或VS2008团队版90天试用版都行。 VS2008专业版90天试用版下载地址&am…

五、Kafka 用户日志上报实时统计之应用概述

一、kafka 回顾 1.简介 Kafka 的业务 业务场景&#xff1a; 解除耦合  增加冗余  提高可扩展性  Buffering  异步通信2.介绍 Kafka 的应用场景 Push MessageWebsite Tracking日志收集中心3.实时统计平台搭建注意事项 实时统计平台搭建注意事项&#xff1a; HA特性核心文…

html5移动web开发黑马掌上商城_这套web前端与移动开发教程,帮助了众多小白转行就业...

前端即网站前台部分&#xff0c;运行在PC端&#xff0c;移动端等浏览器上展现给用户浏览的网页。随着互联网技术的发展&#xff0c;HTML5&#xff0c;CSS3&#xff0c;前端框架的应用&#xff0c;跨平台响应式网页设计能够适应各种屏幕分辨率&#xff0c;完美的动效设计&#x…