Web开发 身份验证 | SpringBoot 整合 JWT | 前后端不分离的案例 | Cookie、Session、Token 、JWT概述与比较

一、Cookie 与 Session


在我们访问页面时,通常是通过 HTTP 协议的,该协议的特点之一是** 无状态**。当我们通过HTTP协议去访问某一个网站,此时就会向网站服务端发送请求。HTTP 协议确保每一个请求都是独立的,于是服务端无法确定当前请求的身份,而 Cookie 和 Session可以解决这个问题。

1.1 Cookie

Cookie 存储在客户端,比如访问网站时的浏览器,每一次请求,Cookie都会自动的发送给服务端,当然这是可以手动禁用的。
Cookie 主要的属性

属性 描述
key=value 键值对,必须都为字符串类型。值为 Unicode字符时,使用字符编码。值为二进制数据时,使用 Base64编码
domain 指定 cookie 所属的域名,默认是当前域名
path 指定 cookie 在哪个路径(即路由)下生效,默认为 ‘/’。若指定为/user,那么只有 /user 下的路由可以访问到该 cookie,如:/user/find
maxAge cookie 失效时间,单位:秒, maxAge < 0 则关闭浏览器就失效,maxAge = 0 ,删除,默认情况maxAge = -1
expires icookie 过期时间,在设置的某个时间后 该 cookie失效。没有 maxAge 好用
secure true / false,表示 cookie 是否使用安全协议(如 HTTPS,SSL)传输,默认为 false。设置为 ture 时, cookie 在HTTP传输中无效,而在 HTTPS 中会有效
httpOnly 禁止通过 JS脚本获取 cookie,但可以通过浏览器调试工具获取到 Application 里的 cookie,能防一定的XSS攻击

1.2 Session

Session 是另一种记录服务端和客户端会话状态的机制,Session 是基于 Cookie 实现的,Session 存储在服务端,当发送请求后,服务端会存储当前请求的sessionId (区分不同的客户端)到 客户端的 Cookie 中。

1.3 Cookie 与 Session 比较

Cookie Session
安全性 不安全,存储在客户端,可自行修改 安全,存储在服务端
存储类型 key为字符串value也为字符串 key为字符串,value 可为能序列化的任何数据
有效期 长时间保持 时间较短,默认为30秒,且在客户端关闭就失效。
存储量 单个Cookie不能超过4K,即4096 Byte 没有固定限制,存储在内存,但是过大会占资源

二、Token


Token 即令牌,分为 Access Token 和 Refresh Token 两种,本次我们用的是 JWT,它是基于Token的,这里以了解为主。

2.1 Access Token

Access Token 是访问资源接口(API)时所需的资源凭证
主要组成: uid + time + sign

  • uid ,用户唯一的身份标识
  • time,当前时间戳
  • sign 签名

特点:

  • 服务端无状态化,可扩展性强
  • 支持移动端设备,现APP里基本上用的都是 Token认证
  • 安全性高
  • 支持跨应用,比如在CSDN中使用微信登录账号。

Access Token 的身份认证流程:

以使用 Token 进行登录的身份认证为例

使用 Access Token 认证的特点:

  • 认证通过后,每次请求都需携带 Token 字符串,通常是放在 HTTP 请求的 Header 请求头
  • 基于 Token 实现的用户认证属于 无状态的认证方式,服务端不用存放 Token 数据。
  • 用解析 Token 的计算时间 换取 Session 的存储与处理时间,减轻服务端压力,减少数据库交互。
  • Token 由客户端管理,成功避开同源策略,即可跨应用进行用户认证

2.2 Refresh Token

Refresh Token 的作用是刷新 Access Token 的 token,若没有 Refresh Token, 同样可以刷新 Access Token,但每次刷新都需要用户输入用户名和密码,带来更多麻烦。

Refresh Token + Access Token 的 认证流程:

使用 Refresh Token 结合 Access Token 的特点:

  • Access Token 有效期比较短,当过期失效时, 使用 Refresh Token 就可以获取到新的 Key,若 RefshToken中也失效,那么用户只能重新登录。
  • Refresh Token 包括其过期时间都存储在服务器的数据库中,只有在申请新的 Acess Token 时才会验证,不会对接口响应时间造成影响,无需像 Session那样保存在内存。

2.3 Token 与 Session 相比

Session Token
服务端状态 有状态化,记录会话信息 无状态化,不存储会话信息
安全性 安全性比Cookie高,但没有Token高,因为SessionId仍然是记录在客户端的 Cookie 里,可进行篡改 更安全,有带加密算法的签名机制
认证机制 支持认证,不可跨应用 支持认证,可以跨应用

三、JWT


JWT,是一种基于 Token 的认证授权机制,是 JSON Web Token 的缩写,是目前最流行的跨域认证采用的技术。

JWT是为了在网络应用环境之间传递声明而执行的一种基于JSON的公开标准(https://datatracker.ietf.org/doc/html/rfc7519

关于 JWT 的 参考教程:http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

3.1 JWT 认证流程

JWT实现原理,以用户登录为例:

JWT 认证流程:

  • 用户携带个人的用户名和密码发送请求,服务端认证成功后,返回客户端一个JWT字符串
  • 客户端将 Token 保存到本地(浏览器的话通常是 localStorage 或 Cookie)
  • 当用户要访问受保护的路由或资源时,需设置 Header 请求头的 Authorization 的值,使用 Bearer 模式 添加 JWT 字符串,比如 Authorization: Bearer <token>
  • 服务端的保护路由会检查 Header 种 Authorization 中的 JWT 信息,若合法则运行用户行为。

使用 JWT 的特点:

  • 内部包含一些会话信息,除了验证、签名生成 JWT外,其他情况无需数据库交互
  • JWT 并不一定依赖于 Cookie,所以可以跨域访问,即支持向第三方应用进行认证与授权
  • 由于用户状态并不存储在服务端的内存,故是一种无状态的认证机制

3.2 JWT 与 Token 相比

JWT 是 Tokne 的拓展,它们之间的 相同点 有:

  • 都是访问资源的令牌
  • 都可以记录用户信息
  • 都使服务端无状态化
  • 都必须通过验证,客户端才能访问服务端受保护的资源

不同点:

Token,服务端 必须 查询数据库获取用户信息,然后再验证 Token 是否有效,

JWT 是将 Token 和 Payload 加密存储在客户端,服务端只需使用密钥解密进行验证,无需查询数据库

3.3 JWT的主要组成

JWT 主要由三部分组成,分别是 header(请求头)、payload(有效负载)、signature(签名),JWT由这三个字符串以句点 . 的方式连接,JWT 通常显示为:xxx.yyy.zzz,即 Header.Payload.Signature

3.3.1 Header

Header 标头通常由两部分组成:

  • 令牌的类型(即 JWT )
  • 签名算法

如 HMAC SHA256 或 RSA,它会用 Base64 编码组成 JWT 结构的第一部分
注:Base64 是一种编码,即是可以进行解码的,并不是一种加密过程。

{
   
  "alg" : "HS256",
  "typ" : "JWT 
}

3.3.2 Payload

令牌的第二部分是 Payload (有效负载),主要存储一些键值对
和 Header 部分一样,Payload 会采用 Base64 编码,不过是作为 JWT 结构的第二部分
例如:

{
   
  "sub": "1234567890",
  "name": "Uni",
  "admin": true
}

3.3.3 Signature

前面两部分都是用 Base64 进行编码的,即前端后端都可以解析里面的信息,Signature 签名需要使用编码后的header 和 payload 以及我们提供的一个字符串密钥,然后使用 header 中指定的签名算法,例如 HS256 进行签名。签名的作用是保证 JWT 没有被篡改过,如:
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);

3.3.4 签名目的

像上述那样,签名的时候同时使用了 header 和 payload 字符串的内容进行组合,
这最后一步的签名过程,实际上是对 Header 头部以及 Payload 负载内容进行签名,防止内容被篡改。若有人对Header 以及 Payload 的内容解码之后再进行修改,再进行编码,最后加上之前的签名组合形成新的JWT的话,那么服务端就会判断出新的头部和负载形成的签名和 JWT 附带上的签名是不一样的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,得出来的签名也是不一样的。

签名的策略有许多,这里只是简单举例,比如我们可以用 payload 里存储的用户ID 和 服务器固定的密钥来进行组合加密,都是可以的。

3.3.5 信息安全问题

Base64 是一种编码方式,是可逆的,那么信息就容易暴露。在JWT中,不应该在 payload 负载里加入任何 敏感 的数据,例如用户的个人密码,不适合放到 JWT。
JWT 经常用于设计用户认证和授权系统,或者实现 Web 应用的单点登录。

四、Cookie Session Token JWT 使用的常见问题


4.1 Cookie

使用 Cookie 需注意的问题:

  • 存储在客户端,容易被篡改,使用前需验证是否合法
  • 尽量不存敏感数据,如用户密码,账号余额
  • 使用 httpOnly ,提高安全性
  • 存储的数据量不能过大,单个Cookie最多只能存储 4kb 的数据
  • 设置正确的 domain 域 和 path,尽量减少数据传输
  • 无法跨域
  • 浏览器对单个网站最多存 20个 Cookie,而浏览器一般指允许存放 300个Cookie
  • 移动端不适合用 Cookie ,而 Session 又是基于 Cookie 实现,故移动端常用 Token

4.2 Session

使用 Session 需注意的问题:

  • 当用户在线过多时,会占据更多内存,需在服务端定期处理过期的 Session
  • 集群环境下,服务端需解决多台 web 服务器共享session的问题,否则同一个用户无法访问服务端不同的web服务器。
  • 共享session 会遇到跨域问题,服务端需在各个应用间解决 cookie 跨域 问题
  • sessionId 存储在客户端的 cookie中,如果浏览器禁止 cookie 或不支持 cookie,可以把 sessionId 写在 URL 参数后面,即 session不一定必须基于 cookie 实现

4.3 Token

使用 Token 需注意的问题:

  • 数据库存储 Token,若导致查询时间长,可选择存放在内存,比如使用 Redis 数据库
  • Token 由应用管理,避免了同源策略的限制。
  • Token 不依赖 Cookie, 可避免 CSRF(跨站域请求伪造)攻击

4.4 JWT

使用 JWT 需注意的问题:

  • JWT 不依赖 Cookie,,支持 CORS 跨域资源共享
  • JWT 默认不加密,不过可设置加密,生成原始Toekn后,再用指定的加密算法加密一次
  • JWT 不加密时不能存放敏感数据,否则有安全隐患
  • JWT 除了认证以外,还可以用来交换信息,降低了服务端的数据库交互
  • JWT 最大优势是服务端无需依赖 Session,方便服务端的认证与授权业务的拓展,同时也有一定局限,无法在使用过程中废弃某个 Token 或 更改 Token 的权限,除非使用更多的逻辑进行处理
  • JWT 本身包含了认证信息,故最好将JWT有效期设置短一些,对于比较重要的权限,使用时应再次验证用户身份
  • JWT 适合一次性的命令认证,颁发有效期很短的JWT,降低泄露的危险
  • 为了降低盗用概率,JWT 应使用 HTTPS 安全协议传输

4.5 整合JWT

JWT 本质上就是一个由点分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递这些字符串,与基于XML的标准(例如SAML)相比,它更紧凑。可通过URL,POST参数或者在HTTP Header 发送,因为数据量小,传输速度快。

五、SpringBoot 整合 JWT


5.1 前后端不分离版

5.1.1 简单版

后端不使用拦截器,前端只通过 HTML ,不写 JavaScript,接下来以最这种最简单的方式来实现 JWT 认证,前后端不分离,前端用 Thymeleaf 模板渲染引擎。

注:这种方式只是用来测试 JWT 功能的,实际开发中很少用

1. 引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.bbs.uni</groupId>
    <artifactId>uni</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>uni</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <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>

        <dependency>
            <groupId>org.springframework.boot</
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值