SpringBootSecurity学习(13)前后端分离版之JWT

JWT 使用

前面简单介绍了把默认的页面登录改为前后端分离的接口异步登录的方法,可以帮我们实现基本的前后端分离登录功能。但是这种基本的登录和前面的页面登录还有一个一样的地方,就是使用session和cookie来维护登录状态,这种方法的问题在于,扩展性不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

一种解决方案是 session 数据持久化,写入redis或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。关于JWT的理论知识,建议参考 阮一峰 大神写的教程 :JSON Web Token 入门教程,这是我认为可能是写的最清晰的一个,下面的jwt的实现也是根据此教程来实现。

具体的理论知识可以参考教程,这里简单说下流程,用户登录成功后,在header中返回用户一个token信息,这个信息里面包含了加密的用户信息和数字签名,最重要的还有过期时间,客户端接到后,每次访问接口header中都带着这个token,服务端验证成功后就表示处于登录状态,过期后再从新获取即可。

具体的token内容包含了头部(加密信息),载体(用户信息),签名(签名两个部分的前面)三大块,三大块之间用英文句号(也就是 ".")连接起来,组成一个完整的token信息

流程设计

根据前面的理论知识,我们来设计一下如何使用jwt。首先我们使用jwt,就可以不再使用session和cookie,所以第一步就是:

  1. 在security配置文件中配置session为无状态。

然后考虑构建jwt消息体,有三个部分,第一个部分就是头部,内容是加密类型:

上面代码中,alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT,最后,将上面的 JSON 对象使用 Base64URL 算法转成字符串,作为第一部分。所以第二步就是:

  1. 在security配置文件中配置session为无状态。
  2. 确定header信息格式

下一步确定第二部分,消息载体(Payload),这也是一个json对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用:

当然除了这些还可以加一些其它内容,比如用户信息,这个 JSON 对象也要使用 Base64URL 算法转成字符串,所以第三步和第四步就是:

  1. 在security配置文件中配置session为无状态。
  2. 确定header信息格式
  3. 确定消息体
  4. 使用 HMAC SHA256 算法 对header和消息体进行签名作为第三部分

现在token的消息基本组合完成了,用户登录成功和客户端访问接口,都要把token放在header里面,名字是 Authorization 。所以最后一步就是,客户端正常访问非登录等接口时,验证token的合法性,所以,总体设计流程如下:

  1. 在security配置文件中配置session为无状态。
  2. 确定header信息格式
  3. 确定消息体
  4. 使用 HMAC SHA256 算法 对header和消息体进行签名作为第三部分
  5. 添加过滤器,验证token合法性

修改配置类

上面的流程设计完了,下面我们按照流程修改项目,首先修改security配置类:

配置完后,启动项目,访问登录,登录成功后可以看到,没有任何cookie保存下来。

定义JWT工具类

首先来定义几个常量:

然后定义Base64URL 算法编码和解码方法:

然后定义HmacSHA256 加密算法和获取签名的方法:

最后来设计一个简单验证token的方法:

这样jwt工具类就设计好了,目前这几个方法足够操作token内容。

定义JWT消息对象

下面来定义jwt的内容,其实内容很简单,就三个部分,因此,定义三个字段即可:

来看一下构造方法,

这个构造方法很便捷,使用它创建对象以后,jwt的三个部分基本都完成了,header部分和payload部分都编码了,签名也完成了,因此下面重写toString方法直接可以生成token:

从这里可以看出,token整体默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。因此不要把密码等重要信息放入token。

修改登录成功处理器

用户登录成功后,不再把session发给用户,而是把jwt发送给用户,因此修改登录成功处理器如下:

注意上面手动把用户的密码信息设置为null。这里为了方便,直接使用fastjson组合对象。

修改实体类

带着token访问接口的时候,需要把token转回登录用户对象,因此我们的用户实体类和token中带的字段名字一致,来修改一下,先看角色实体类:

再看用户实体类:

可以看到,基本的原则就是修改的名字和父类的必要字段名字一致就行,这也是建议的字段名字。

编写token验证过滤器

我们把security的session改为无状态后,虽然不再传递session,但是security的过滤器并没有失效,因此造成的效果就是登录成功后,访问接口显示未登录。现在我们使用token就要在登录前加一个验证token的过滤器,验证通过后直接把信息放到SecurityContextHolder中。这样每次登录靠验证token来判断是否登录,不再靠session。来看这个过滤器:

这个过滤器很简单,继承了 GenericFilterBean 类,直接获取token,判断token不为空,验证token,并从token的payload中取出用户信息,放入SecurityContextHolder中,验证失败或者token过期直接返回token错误。逻辑很简单。

最后在security类中,把这个过滤器配置到前面:

这样我们自定义的jwt流程就完成了。可以在postman中测试一下,首先是登录:

登录成功后,可以看到header中放着token的信息,然后使用token放入另一个接口的header中访问接口,可以看到访问成功:

有兴趣的可以debug跟踪一下流程。

JWT的几个特点

  • (1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
  • (2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
  • (3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
  • (4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
  • (5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
  • (6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。

代码地址:https://gitee.com/blueses/spring-boot-security 14

原文地址:https://www.cnblogs.com/guos/p/11622273.html

时间: 2024-10-09 23:06:00

SpringBootSecurity学习(13)前后端分离版之JWT的相关文章

SpringBootSecurity学习(12)前后端分离版之简单登录

前后端分离 前面讨论了springboot下security很多常用的功能,其它的功能建议参考官方文档学习.网页版登录的形式现在已经不是最流行的了,最流行的是前后端分离的登录方式,前端单独成为一个项目,与后台的交互,包括登录认证和授权都是由异步接口来实现.在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高.这种应用模式比较适合纯网页应用, 但是当后端对接App时,App可能并不需要后端返回一个HTML网页,而

SpringBootSecurity学习(15)前后端分离版之 OAuth2.0简单示例

OAuth2.0 OAuth 引入了一个授权层,用来分离两种不同的角色:客户端和资源所有者.客户端来申请资源,资源所有者同意以后,资源服务器可以向客户端颁发令牌.客户端通过令牌,去请求数据.也就是说,OAuth 的核心就是向第三方应用颁发令牌.而且,OAuth 2.0 规定了四种获得令牌的流程.你可以选择最适合自己的那一种,向第三方应用颁发令牌. 具体的OAuth学习建议仔细研读阮一峰的教程, http://www.ruanyifeng.com/blog/2019/04/oauth_design

SpringBootSecurity学习(26)前后端分离版之github单点登录

单点登录(SSO) 关于oauth2.0,最后我们再来学习一下单点登录.前面介绍过单点登录的定义,单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 关于单点登录,springcloud G版本的官方文档地址如下: https://cloud.spring.io/spring-cloud-static/Greenwich.SR3/single/spring-cl

SpringBootSecurity学习(18)前后端分离版之 OAuth2.0 数据库(MyBatis)存储客户端

使用Mybatis查询客户端信息 前面的例子使用了默认的jdbc配置来动态从数据库查询客户端信息,下面来改用更加灵活的mybatis来实现,改用mybatis,首先pom中换成mybatis的依赖: 然后新建一个实体类,并实现查询需要的 ClientDetails 接口: 由于接口默认需要实现的方法有很多返回类型为集合类型的,所以这里的部分get方法做一些调整,例如: 其它的可以自行下载源代码查看.实体类建好以后,我们就可以查询客户端了: 实现 ClientDetailsService 接口 查

SpringBoot 和Vue前后端分离入门教程(附源码)

作者:梁小生0101 juejin.im/post/5c622fb5e51d457f9f2c2381 推荐阅读(点击即可跳转阅读) 1. SpringBoot内容聚合 2. 面试题内容聚合 3. 设计模式内容聚合 4. 排序算法内容聚合 5. 多线程内容聚合 前端工具和环境: Node.js V10.15.0 Vue.js V2.5.21 yarn: V1.13.0 IDE:VScode 后端工具和环境: Maven: 3.52 jdk: 1.8 MySql: 14.14 IDE: IDEA S

七个开源的 Spring Boot 前后端分离项目,一定要收藏!

前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开发,以免在公司干了两三年,SSH 框架用的滚瓜烂熟,出来却发现自己依然没有任何优势! 其实前后端分离本身并不难,后段提供接口,前端做数据展示,关键是这种思想.很多人做惯了前后端不分的开发,在做前后端分离的时候,很容易带进来一些前后端不分时候的开发思路,结果做出来的产品不伦不类,因此松哥这里给大家整理了几个开源的前后端分离项

从壹开始前后端分离【 .NET Core2.0 Api + Vue 3.0 + AOP + 分布式】框架之九 || 依赖注入IoC学习 + AOP界面编程初探

代码已上传Github,文末有地址 说接上文,上回说到了<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之八 || API项目整体搭建 6.3 异步泛型+依赖注入初探>,后来的标题中,我把仓储两个字给去掉了,因为好像大家对这个模式很有不同的看法,嗯~可能还是我学艺不精,没有说到其中的好处,现在在学DDD领域驱动设计相关资料,有了好的灵感再给大家分享吧. 到目前为止我们的项目已经有了基本的雏形,后端其实已经可以搭建自己的接口列表了,框架已

从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十一║Vue实战:开发环境搭建【详细版】

系列教程一目录:.netcore+vue 前后端分离 系列教程二目录:DDD领域驱动设计 系列教程三目录:Nuxt.js TiBug系统 系列教程四目录:VueAdmin 后台管理系统 系列教程五目录:IdentityServer4 授权服务器 本文梯子 缘起 零.今天要完成左下角红色的部分 A.Vue 常见的IDE —— 我是开发工具,干活的都是我 1.VsCode 2.Webstorm 3.Atom B.安装Nodejs环境 —— 我是运行环境,没我不行 C.安装 npm / cnpm ——

学习 Antd Pro 前后端分离

1.前言 最近学习reactjs ,前些年用RN开发过移动端,入门还算轻松.现在打算使用 Antd Pro 实现前后端分离.要使用Antd Pro这个脚手架,必须熟悉 umi.dva.redux-saga 等相关知识. 基础知识及目录结构可以先看官方文档 : https://pro.ant.design/docs/getting-started-cn 官方介绍: Ant Design Pro 是一个企业级中后台前端/设计解决方案,我们秉承 [Ant Design](http://ant.desi