基于JWT的身份验证

Posted So istes immer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于JWT的身份验证相关的知识,希望对你有一定的参考价值。

目录

JWT(JSON Web Token)是目前最流行的跨域认证解决方案

1.跨域认证的问题

互联网服务中的用户认证流程:

1.用户向服务器发送用户名和密码

2.服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等

3.服务器向用户返回一个session_id,写入用户的Cookie

4.用户随后的每一次请求,都会通过Cookie将session_id传回服务器

5.服务器收到session_id,找到前期保存的数据,由此得知用户的身份

该模式的缺点在于,扩展性(scaling)不好。单机没问题,如果是服务器集群或者是跨域的服务导向架构,就要求session数据共享,每台服务器都能够读取session

举例:

A网站和B网站是用一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问如何实现?

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

解决方案②:服务器索性不保存session数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT就是这种方案的一个代表。

2.JWT原理

服务器认证之后,生成一个JSON对象,发回给用户。以后,用户与服务器通信的时候,都要发回这个JSON对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器再生成这个对象的时候,会加上签名。

服务器就不保存任何session数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

3.JWT的数据结构

实际的JWT是一个很长的字符串,中间用点(.)分隔成三个部分。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT的三个部分:Header(头部).Payload(负载).Signature(签名)

测试JWT网站:https://jwt.io/

Header

Header部分是一个JSON对象,描述JWT的元数据,如下

{
  "alg": "HS256",    //表示签名的算法
  "typ": "JWT"        //表示token的type,JWT令牌的type就是JWT
}

将该JSON对象用Base64URL算法转成字符串

Payload

Payload部分也是一个JSON对象,用来存放实际需要传递的数据。JWT规定了7个官方字段

iss(issuer): 签发人

exp(expiration time):过期时间

sub(subject):主题

aud(audience): 受众

nbf(Not Before): 生效时间

iat(Issued At): 签发时间

iti(JWT ID):编号

除了官方字段,也可以自定义私有字段,但是不要把私密信息放在这个部分,因为JWT默认不加密

这个JSON对象也要使用Base64URL算法转成字符串

Signature

Signature部分是对前两部分的签名,防止数据篡改

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后使用Header里面

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
) 

算出签名之后,将Header、Payload、Signature三个部分拼成一个字符串,每个部分用“点”分隔,就可以返回给用户。

在JWT中,消息体是透明的,使用签名可以保证消息不被篡改。但不能实现数据加密功能。

Base64URL算法和Base64算法差不多。

4.JWT的使用方式

客户端收到服务器返回的JWT,可以存储在Cookie里面,也可以存储在localStorage

此后,客户端每次与服务器通信,都要带上这个JWT。你可以把它放在Cookie里面自动发送,但是这样不能跨域,所以更好的做法是放在HTTP请求的头信息Authorization字段里面。

另一种做法是跨域的时候,JWT就放在POST请求的数据体里面。

JWT的最大缺点是,由于服务器不保存session状态,因此无法在使用过程中废止某个token,或者更改token的权限。也就是说一旦JWT签发了,在到期之前就会始终有效。

什么是跨域?
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
域名:
 主域名不同 http://www.baidu.com/index.html -->http://www.sina.com/test.js
 子域名不同 http://www.666.baidu.com/index.html -->http://www.555.baidu.com/test.js
 域名和域名ip http://www.baidu.com/index.html -->http://180.149.132.47/test.js
端口:
 http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
协议:
 http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
备注:
 1、端口和协议的不同,只能通过后台来解决
 2、localhost和127.0.0.1虽然都指向本机,但也属于跨域

在Node.js中使用JWT https://github.com/auth0/node-jsonwebtoken

以上是关于基于JWT的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

基于Token的身份验证——JWT(转)

在 Spring Boot 2 上实现基于过滤器的 JWT 身份验证与 OAuth2 JWT 身份验证

混合身份验证 - 基于 Spring MVC 会话 + 基于 JWT 令牌

使用 Spring 和 JWT 进行基于令牌的身份验证

这种基于 JWT 的身份验证方法安全吗?

使用 Jwt 的基于令牌的身份验证无法授权