前言

《玩转 SpringBoot 2 之整合 JWT 上篇》 中介绍了关于 JWT 相关概念和JWT 基本使用的操作方式。本文为 SpringBoot 整合 JWT 的下篇,通过解决 App 用户登录 Session 问题的实战操作,带你更深入理解 JWT。通过本文你还可以了解到如下内容:

  1. SpringBoot 使用拦截器的实际应用
  2. SpringBoot 统一异常处理
  3. SpringBoot 快速搭建 RESTful Api

关于生成JWT 操作请参考 《玩转 SpringBoot 2 之整合 JWT 上篇》

实战操作

登录操作

登录操作流程图:

登录操作流程介绍:

  1. App 根据用户名和密码访问登录接口。
  2. 如果用户名和密码错误则提示 App 用户密码输入错误。
  3. 如果用户名和密码正确则获取用户信息(表示登录成功)并根据用户信息生成 Token 并将其存入ServletContext 中。
  4. 将生成的 Token 返回给 App。

登录操作具体代码:

@RestController
public class LoginController {
Logger log = LoggerFactory.getLogger(LoginController.class);
@Autowired
private JWTService jwtService; @RequestMapping("/login")
public ReturnMessage<Object> login(String loginName,String password,HttpServletRequest request) {
if(valid(loginName,password)) {
ReturnMessageUtil.error(CodeEnum.LOGINNAMEANDPWDERROR);
} Map<String,String> userInfo = createUserInfoMap(loginName,password);
String token = jwtService.createToken(userInfo, 1); ServletContext context = request.getServletContext();
context.setAttribute(token, token);
log.info("token:"+token);
return ReturnMessageUtil.sucess(token);
}
} private Map<String,String> createUserInfoMap(String loginName, String password) {
Map<String,String> userInfo = new HashMap<String,String>();
userInfo.put("loginName", loginName);
userInfo.put("password", password);
return userInfo;
} private boolean valid(String loginName, String password) {
if(Objects.equal("ljk", loginName) && Objects.equal("123456", password) ) {
return true;
}
return false;
}

拦截操作

拦截操作流程图:

拦截操作流程介绍:

  1. 服务器获取 (App访问具体的Api 时携带的 Token)Token,如果 Token 为空则提示 App Token不能为空。

  2. 如果 Token 不为空则从 ServletContext 中获取 Token,如果不存在则提示 App 该Token为非法 Token !

  3. 如果 Token 不为空并且 ServletContext 中存在该Token,需要判断 Token 是否过期。如果未过期则放开拦截。

  4. 如果Token 已经过期则提示 App Token已经过期,需要重新登录。

拦截操作具体代码:

public class LoginInterceptor implements HandlerInterceptor{

	Logger log = LoggerFactory.getLogger(LoginInterceptor.class);

	private JWTService jwtService;

	public LoginInterceptor(JWTService jwtService) {
this.jwtService = jwtService;
} public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception { log.info("Token Checkout processing");
String token = request.getParameter("token"); if (StringUtils.isEmpty(token)) {
throw new JKException(CodeEnum.TOKENISEMPTY);
} String tokenInServletContext = (String)request.getServletContext().getAttribute(token);
if(StringUtils.isEmpty(tokenInServletContext)) {
throw new JKException(CodeEnum.ILLEGALTOKEN);
} try {
jwtService.verifyToken(token);
} catch (AlgorithmMismatchException e) {
log.error("Token Checkout processing AlgorithmMismatchException 异常!"+e.getLocalizedMessage());
throw new JKException(CodeEnum.ILLEGALTOKEN);
}catch (TokenExpiredException e) {
log.info("token已经过期");
throw new JKException(CodeEnum.EXPIRETOKEN);
}catch (SignatureVerificationException e) {
log.error("Token Checkout processing SignatureVerificationException 异常!"+e.getLocalizedMessage());
throw new JKException(CodeEnum.ILLEGALTOKEN);
}catch (Exception e) {
log.error("Token Checkout processing 未知异常!"+e.getLocalizedMessage());
throw e;
} return true;
}
}

退出操作

退出操作流程介绍:

访问退出接口并传递登录生成的 Token,然后将 ServletContext中的 Token 删除。

退出操作具体代码:

	@GetMapping("/logout")
public ReturnMessage<?> logout(String token,String issuer,HttpServletRequest request) {
ServletContext context = request.getServletContext();
context.removeAttribute(token);
return ReturnMessageUtil.sucess();
}

公共代码

IndexController App 访问测试Api,具体代码如下:

@RestController
public class IndexController { @GetMapping("index")
public ReturnMessage index() {
return ReturnMessageUtil.sucess();
}
}

统一异常次处理的 Handle

@RestControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
//@ResponseBody
public ReturnMessage<Object> handle(HttpServletResponse response, Exception exception) {
response.setCharacterEncoding("utf-8");
if(exception instanceof JKException) {
JKException sbexception = (JKException)exception;
return ReturnMessageUtil.error(sbexception.getCode(), sbexception.getMessage());
}else {
logger.error("系统异常 {}",exception);
return ReturnMessageUtil.error(-1, "未知异常"+exception.getMessage());
}
}
}

JWTService 工具类 代码可以在我的GitHub上进行查看,具体地址请查看下面代码示例章节。

测试

这里使用PostMan 进行测试,当然你也可以选用你顺手的工具进行测试哈!

访问 http://localhost:8080/sbe/login?loginName=ljk&password=123456 进行登录获取Token,如下图所示date字段的值就是登录成功后生成的 Token。

访问 http://localhost:8080/sbe/index?token=具体token值,如下图所示访问成功!

如果不携带 Token 会提示Token不能为空,如下图所示:

如果输入不存在的 Token 则提示 非法Token!,如下图所示:

http://localhost:8080/sbe/logout?token=具体token值 进行退出,如下图所示:

退出后再次使用已经退出的Token 访问,会提示非法Token 如下图所示:

小结

登录操作通过 JWT 生成Token 返回给App,拦截操作(也可以理解成校验操作)通过拦截器(HandlerInterceptor)来进行实现。最后退出操作是通过将Token 保存ServletContent 中,退出其实就是将 Token 从 ServletContent 中删除。

本文主旨是通过简单实现,带你了解 App 认证过程处理方式,对于拦截部分你也可以通过 Filter 或 Aop 来进行实现。Token 存储也可以考虑使用Redis来实现,还有一个问题就是:JWT 续期问题本文并没有实现(JWT 过期时间延期问题)。这个部分就当成一个作业,欢迎大家在评论区说说你的解决方案?

代码示例

本文并没有对 JWTService 工具类、统一异常处理、拦截器使用搭建进行详细介绍,如果你想直接查看本文全部源码,请在我的GitHub 仓库 SpringbootExamples 中的 spring-boot-2.x-jwt 模块进行查看。

GitHub:https://github.com/zhuoqianmingyue/springbootexamples

同时你也可以通过查看我关于拦截器、统一异常处理、搭建 RESTful Api 详细教程总结自己完成相关的实现:

玩转 SpringBoot 2 之整合 JWT 下篇的更多相关文章

  1. 玩转 SpringBoot 2 之整合 JWT 上篇

    前言 该文主要带你了解什么是 JWT,以及JWT 定义和先关概念的介绍,并通过简单Demo 带你了解如何使用 SpringBoot 2 整合 JWT. 介绍前在这里我们来探讨一下如何学习一门新的技术, ...

  2. 玩转 SpringBoot 2 快速整合 | 丝袜哥(Swagger)

    概述 首先让我引用 Swagger 官方的介绍: Design is the foundation of your API development. Swagger makes API design ...

  3. 玩转 SpringBoot 2 快速整合拦截器

    概述 首先声明一下,这里所说的拦截器是 SpringMVC 的拦截器 HandlerInterceptor.使用SpringMVC 拦截器需要做如下操作: 创建拦截器类需要实现 HandlerInte ...

  4. 玩转 SpringBoot 2 快速整合 | FreeMarker篇

    FreeMarker 介绍 Apache FreeMarker™是一个模板引擎:一个Java库,用于根据模板和更改数据生成文本输出(HTML网页,电子邮件,配置文件,源代码等).模板是用FreeMar ...

  5. 玩转 SpringBoot 2 快速整合 | JSP 篇

    前言 JavaServer Pages(JSP)技术使Web开发人员和设计人员能够快速开发和轻松维护利用现有业务系统的信息丰富的动态Web页面. 作为Java技术系列的一部分,JSP技术可以快速开发独 ...

  6. 玩转 SpringBoot 2 快速整合 | Thymeleaf 篇

    前言 Thymeleaf是一个适用于Web和独立环境的现代服务器端Java模板引擎. Thymeleaf的主要目标是为您的开发工作流程带来优雅的自然模板 - 可以在浏览器中正确显示的HTML,也可以用 ...

  7. 玩转 SpringBoot 2 快速整合 Filter

    概述 SpringBoot 中没有 web.xml, 我们无法按照原来的方式在 web.xml 中配置 Filter .但是我们可以通过 JavaConfig(@Configuration +@Bea ...

  8. 教你 Shiro + SpringBoot 整合 JWT

    本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...

  9. SpringBoot整合JWT实现登录认证

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

随机推荐

  1. 感受一下.net中用 lambda与 linq 做数据集过滤的不同

    lambda: ids.Add( _hahahacontext .hahahamodel .FirstOrDefault( a => //lambda做过滤 a.name == "张宏 ...

  2. 工作中遇到的99%SQL优化,这里都能给你解决方案

    前几篇文章介绍了mysql的底层数据结构和mysql优化的神器explain.后台有些朋友说小强只介绍概念,平时使用还是一脸懵,强烈要求小强来一篇实战sql优化,经过周末两天的整理和总结,sql优化实 ...

  3. 转载java 8 为什么引入 lambda

    转载:https://www.cnblogs.com/keeya/p/11404631.html 在Java8出现之前,如果你想传递一段代码到另一个方法里是很不方便的.你几乎不可能将代码块到处传递,因 ...

  4. Codeforces 938D Buy a Ticket

    Buy a Ticket 题意要求:求出每个城市看演出的最小费用, 注意的一点就是车票要来回的. 题解:dijkstra 生成优先队列的时候直接将在本地城市看演出的费用放入队列里, 然后直接跑就好了, ...

  5. andriod开发--使用Http的Get和Post方式与网络交互通信

    package com.example.a350773523.myapplication; import android.os.AsyncTask; import android.support.v7 ...

  6. POJ 1390 Blocks (区间DP) 题解

    题意 t组数据,每组数据有n个方块,给出它们的颜色,每次消去的得分为相同颜色块个数的平方(要求连续),求最大得分. 首先看到这题我们发现我们要把大块尽可能放在一起才会有最大收益,我们要将相同颜色块合在 ...

  7. EditPlus5.0破解激活

    永久激活用户名激活码: 用户名:Vovan注册码:3AG46-JJ48E-CEACC-8E6EW-ECUAW 然后重启软件即可

  8. CSAPP DataLab

    注意不同版本的题目可能会有所不同,搜了很多他们的题目和现在官网给的实验题都不一样,自己独立思考完整做一遍顺便记录一下. PS:这些难度为1的题有的说实话我都做了挺久的,不过完整做一遍感觉很有意思,这些 ...

  9. idea取消大小写自动提示

    file-settings 取消勾选Match case

  10. 误删除系列一:linux的bin目录误删除后恢复操作

    感言:一失足成千古恨,一不小心就把/usr/bin下所有的命令都删除了,当你以为自己很熟练时,当你以为自己操作对时,可能就是失手的时候,还好这次只是一个测试环境....God 恢复过程:(以下是在vs ...