JWT跨域认证解决方案

1,158 阅读3分钟

一、什么是JWT

JSON Web Token(缩写 JWT),是目前最流行的一个跨域认证解决方案:客户端发起用户登录请求,服务器端接收并认证成功后,生成一个 JSON 对象(如下所示),然后将其返回给客户端。客户端再次与服务器端通信的时候,把这个 JSON 对象捎带上,作为前后端互相信任的一个凭证。服务器端接收到请求后,通过 JSON 对象对用户身份进行鉴定,这样就不再需要保存任何 session 数据了。

访问JWT官网可对JWT(如同很长的字符串,中间用点(.)分隔成三个部分)进行解码,解码的内容由HEADER、PAYLOAD和VERIFY SIGNATURE三个部分组成。

image.png

HEADER : ALGORITHM & TOKEN TYPE

Header 部分是一个 JSON 对象,描述 JWT 的元数据。alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT

PAYLOAD : DATA

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

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

VERIFY SIGNATURE

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

首先指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

Base64URL算法

Header 和 Payload 的串型化都是使用的Base64URL算法。

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

可参考文档:阮一峰的JSON Web Token 入门教程

二、JWT的简单使用

引入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>${jjwt.version}</version>
</dependency>

yml文件配置

# 登录认证 token filter
jwt:
  tokenHeader: Authorization #JWT存储的请求头
  secret: codingmore-admin-secret #JWT加解密使用的密钥
  expiration: 604800 #JWT的超期限时间(60*60*24*7)
  tokenHead: 'Bearer '  #JWT负载中拿到开头

JwtTokenUtil

使用JwtTokenUtil工具类完成JWT的生成,以及是否过期的判断

JwtTokenUtil存在三种方法完成主要功能

  • generateToken(UserDetails userDetails):根据登录用户生成 token
  • getUserNameFromToken(String token):从 token 中获取登录用户
  • validateToken(String token, UserDetails userDetails):判断 token 是否仍然有效

每次调用登录接口,后端都可把生成的JWT返回给前端,让前端保存在localStorage中

{
    "code": 0,
    "message": "操作成功",
    "result": {
        "tokenHead": "Bearer ",
        "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJzdG9ob3giLCJjcmVhdGVkIjoxNjU0MTQzODYzNDc5LCJleHAiOjE2NTQ3NDg2NjN9.qyZ0_UpKrN6lsX5gxqOeS8AuJdE3hQXeL_GPURbnnD-lG6yTHC-i8xR1GWHNccN0kFDlNXKKXHRo30uye-cbHw"
    }
}

JwtAuthenticationTokenFilter

新建JwtAuthenticationTokenFilter过滤器继承OncePerRequestFilter,以保证客户端每发起一次请求,该过滤器只会执行一次。

JWT 和 Session 的根本区别:

  • JWT 需要每次请求的时候验证一次,并且只要 JWT 没有过期,哪怕服务器端重启了,认证仍然有效。
  • Session 在没有过期的情况下是不需要重新对用户信息进行验证的,当服务器端重启后,用户需要重新登录获取新的 Session。

前端在调取后端接口时,则需要在请求头上增加Authorization,内容为之前保存的JWT,并在JWT前加“Bearer”,用空格隔开。否则请求将会被过滤器过滤。

image.png

项目地址: github.com/itwanger/co…

参考文章:spring security系列一:架构概述 - SegmentFault 思否

再见Session!这个跨域认证解决方案真的优雅