基于JWT的Token认证机制实现

2019-08-17  本文已影响0人  djm猿

1 常见的认证机制

1.1 HTTP Basic Auth

HTTP Basic Auth简单点说明就是每次请求API时都提供用户的 username 和 password,简言之,Basic Auth 是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic
Auth。

1.2 Cookie Auth

Cookie 认证机制就是为一次请求认证在服务端创建一个 Session 对象,同时在客户端的浏览器端创建了一个Cookie 对象;通过客户端带上来 Cookie 对象来与服务器端的 session 对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie 会被删除。但可以通过修改cookie 的 expire time 使 cookie 在一定时间内有效。

1.3 Oauth

OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在某一 web 服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。

1.4 Token Auth

Token机制相对于Cookie 机制又有什么好处呢?

2 基于JWT的Token认证机制实现

2.1 什么是 JWT?

JSON Web Token(JWT)是一个非常轻巧的规范,这个规范允许我们使用 JWT 在用
户和服务器之间传递安全可靠的信息。

2.2 JWT 组成

一个 JWT 实际上就是一个字符串,由头部、载荷和签名组成

2.2.1 头部

头部用于描述 JWT 最基本的信息,例如其类型、签名使用的压缩算法等,它可以被表示为一个 json 对象:

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

在头部指定了签名算法是 HS256 算法,我们进行 Base64 编码,编码后的字符串如下:

eyJ0eWUiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9

2.2.2 载荷

载荷就是存放有效信息的地方

载荷(Payload)

{ "iss": "Online JWT Builder", 
  "iat": 1416797419, 
  "exp": 1448333419, 
  "aud": "www.example.com", 
  "sub": "djm@example.com", 
  "GivenName": "djm", 
  "Surname": "DJM", 
  "Email": "djm@example.com", 
  "Role": [ "Manager", "Project Administrator" ] 
}

将上面的 JSON 对象进行 base64 编码可以得到下面的字符串,这个字符串我们将它称作JWT的Payload

eyAiaXNzIjogIk9ubGluZSBKV1QgQnVpbGRlciIsIAogICJpYXQiOiAxNDE2Nzk3NDE5LCAKICAiZXhwIjogMTQ0ODMzMzQxOSwgCiAgImF1ZCI6ICJ3d3cuZXhhbXBsZS5jb20iLCAKICAic3ViIjogImRqbUBleGFtcGxlLmNvbSIsIAogICJHaXZlbk5hbWUiOiAiZGptIiwgCiAgIlN1cm5hbWUiOiAiREpNIiwgCiAgIkVtYWlsIjogImRqbUBleGFtcGxlLmNvbSIsIAogICJSb2xlIjogWyAiTWFuYWdlciIsICJQcm9qZWN0IEFkbWluaXN0cmF0b3IiIF0gCn0=

2.2.3 签证

这个签证信息由三部分组成:header(base64)、payload(base64)、secret,中间使用 . 连接,然后使用 header 声明的的加密方式进行加言 secret 组合加密,就构成了第三部分

3 JWT 实现 JJWT

3.1 什么是 JJWT

JJWT 是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。

3.2 JJWT 快速入门

3.2.1 token的创建

public String createJWT(String id, String subject, String roles) {
    // 当前计算机时间
    long nowMillis = System.currentTimeMillis();
    Date now = new Date(nowMillis);
    JwtBuilder builder = Jwts.builder()
        .setId(id)
        // 设置用户
        .setSubject(subject)
        // 设置签约时间
        .setIssuedAt(now)
        // 签名和使用签名压缩算法、
        .signWith(SignatureAlgorithm.HS256, key)
        // 设置claims
        .claim("roles", roles);
    if (ttl > 0)
        builder.setExpiration(new Date(nowMillis + ttl));
    return builder.compact();
}

Jwts.builder() 返回了一个 DefaultJwtBuilder()

DefaultJwtBuilder 的属性,如下:

private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private Header header; //头部
private Claims claims; //声明
private String payload; //载荷
private SignatureAlgorithm algorithm; //签名算法
private Key key; //签名key
private byte[] keyBytes; //签名key的字节数组
private CompressionCodec compressionCodec; //压缩算法

setHeader() 有两种参数形式,一种是 Header 接口的实现,一种是 Map, 其实 Header 接口也集成自 Map,如过以 Map 作为参数,在 setHeader 的时候会生成默认的 Header 接口实现 DefaultHeader。

如果不设置签名,也不进行压缩,alg 也应该存在,否则,对其解析就会报错,在生成 jwt 时,如果不设置签名,可将 alg 设置为 none

setPayload() 设置payload,直接赋值

setClaims() 设置claims,以参数创建一个新Claims对象,直接赋值

claim() 如果 builder 中 Claims 属性为空,则创建 DefaultClaims 对象,并把键值放入;如果 Claims 属性不为空,获取之后判断键值,存在则更新,不存在则直接放入。

当然也可以在Payload中添加一些自定义的属性claims键值对

JJWT 还提供了 JWT标准7个保留声明(Reserved claims)的设置方法,7个声明都是可选的,也就是说可以不用设置。

当然也可以在Payload中添加一些自定义的属性claims键值对

compressWith() 压缩方法。当载荷过长时可对其进行压缩。可采用jjwt实现的两种压缩方法CompressionCodecs.GZIP、CompressionCodecs.DEFLATE

signWith() 签名方法:两个参数分别是签名算法和自定义的签名Key。签名 key 可以 byte[] 、String 及 Key 的形式传入,前两种形式均存入 builder 的 keyBytes 属性,后一种形式存入 builder 的 key 属性,如果是第二种 key,则将其进行 base64 解码获得 byte[] 。

compact() 生成JWT

3.2.2 token 解析

public Claims parseJWT(String jwtStr) {
    return Jwts.parser()
        .setSigningKey(key)
        .parseClaimsJws(jwtStr)
        .getBody();
}
上一篇下一篇

猜你喜欢

热点阅读