聊一聊JWT(JSON WEB TOKEN)鉴权

JWT   

定义:

Json web  token 是一个开发标准,它定义了一种紧凑且自包含的方式,用于在各方之间安全地将信息作为json对象传输。

由于此信息是经过数字签名的,因此可以被验证和信任。可以使用密钥(HMAC算法)或使用RSA的公/私钥对JWT进行签名。

了解下定义的一些概念:

紧凑:由于其大小,它可以通过url,post参数或Http表头发送。另外,由于其内存空间较小,其传输速度很快。

自包含:有效负载包含有关用户的所有必须信息,以避免多次查询数据库或者查询相关缓存带来的相关性能问题。

什么时候使用JSON WEB令牌?

在以下情况下,JSON WEB令牌很有用:

身份验证:这是使用JWT的典型方案,一旦用户登录,每个后续的请求都将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以很轻松的不同域的系统中使用。

信息交换:JWT在各方面之间安全的传输信息的一种好方法,因为可以对他们进行签名,因此可以确定发送者是他们所说身份。此外,由于签名是使用标头和有效负载计算的,因此可以验证内容有没有被进行修改。

JSON WEB令牌结构是什么?

JWT由三部分组成,每一部分之间用(.)进行分割,分别是:

标头

有效负载

签名

因此JWT通常内容如下所示:

xxxx.yyyyy.zzzzz

标头:

通常有两部分组成:令牌的类型(即JWT)和哈希算法(例如:HMAC SHA256或者RSA)

例如:

{

  "alg": "HS256",

  "typ": "JWT"

}

有效负载:

令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他元数据的声明。有三种类型的声明:保留 公共 和私有声明

1.保留:这些是一组预定义的权利要求,不是强制性的,而是建议使用的,它们被认为可以提供一组有用的,可互操作的权利要求。其中一些是:iss(发行者),exp(到期时间),sub(主题),  aud(受众)等等。

请注意,声明名称仅是三个字符,因为JWT是紧凑的。

2.公共声明:使用JWT的人员可以随意定义这些声明。

3.私人声明:这些是为在同意使用它们的各方之间共享信息而创建的自定义声明。

有效负载的示例可能是:

{

  "sub": "1234567890",

  "name": "John Doe",

  "admin": true

}

然后对有效负载进行Base64Url编码,以形成JWT的第二部分。

签名

要创建签名部分,您必须获取编码的标头,编码的有效负载,密钥,标头中指定的算法,并对其进行签名。

例如,如果要使用HMAC SHA256算法,则将以以下方式创建签名。

HMACSHA256(

  base64UrlEncode(header) + "." +

  base64UrlEncode(payload),

  secret)

该签名用于验证JWT的发件人是谁,并确保该消息没有以这种方式更改。

放在一起

输出是由点分隔的三个Base64字符串,这些字符串可以在HTML和HTTP环境中轻松传递,并且与基于XML的标准(例如SAML)相比更加紧凑。

下图显示了一个JWT,它已对先前的标头和有效负载进行了编码,并用一个秘密进行了签名。

JSON WEB令牌如何工作?

在身份验证中,当用户使用其凭据成功登录时,将返回JSON web令牌。由于令牌是凭据,因此必须格外小心以防止安全问题。

通常,令牌的保留时间不应该超过要求的时间。

由于缺乏安全性,您也不应该将敏感的会话数据存储在浏览器中。

每当用户想要访问受保护的路由时,通常应该Bearer模式下的Authorization header中发送JWT。因此,标头的内容如下所示:

Authorization: Bearer <token>

这是一种无状态的身份验证机制,因为用户状态永远不会保存在服务器的内存中。服务器的受保护路由将在Authorization标头中检查有效的JWT,如果存在,则将允许该用户。由于JWT是独立的,因此所有必须的信息都在其中,从而减少了往返数据库的需求。

这允许完全无状态的数据API,甚至可以向下游服务器发送请求,哪个域为您的api服务都没有关系,因为跨域资源共享cors不会使用cookie,因此不会成为问题。

为什么要使用JSON web令牌呢?

JSON WEB 令牌与简单web令牌 SWT 和安全性声明标记语言令牌SAML相比的优势。

由于JSON不如xml冗长,因此在编码时,它的大小也较小,使得JWT比SAML更紧凑。这使得JWT是在HTML和HTTP环境中传递的不错的选择.

在安全方面,只能使用HMAC算法由共享密钥对SWT进行对称签名。同时JWT和SAML令牌还可以使用X.509证书形式的公共/私有密钥对其进行签名。但是与简单签名JSON相比,使用XML Digital Signature签名XML而不引入模糊的安全漏洞是非常困难的。

JSON解析器在大多数编程语言中都很常见,因为它们直接映射到对象,相反,XML没有自然的文档到对象的映射。这使得使用JWT比使用SAML断言更加容易。

关于用法,JWT是在Internet规模上使用的。这突出了在多个平台(尤其是移动平台)上对JWT进行客户端处理的简便性。

我们如何在AUTH0中使用JSON WEB令牌?

在Auth0中,由于身份验证过程,我们发出了JWT。当用户使用Auth0登录时,将创建,签名JWT并将其发送给用户。Auth0支持使用HMAC和RSA算法签名JWT。然后,此令牌将用于通过API进行身份验证和授权,这些API将授予对其受保护的路由和资源的访问权限。

我们还使用JWT在Auth0的API v2中执行身份验证和授权,以取代常规的不透明API密钥的传统用法。关于授权,JSON Web令牌允许细粒度的安全性,即在令牌中指定一组特定权限的能力,从而提高了可调试性。

详细了解可以点击此链接

JWT官网地址

简单介绍下创建,解析和验证,已经验证过,具体根据自己的场景来进行定义。


    /**
     * 创建JWT签名
     *
     * @param userId
     * @return
     * @throws Exception
     */
    public static String createJWT(String userId) throws Exception {
        Long expireTime = 28800000L;
        Date expiresDate = new Date(System.currentTimeMillis() + expireTime);
        try {
            Algorithm algorithm = Algorithm.HMAC256(APP_SECRET);
            String token = JWT.create()
                    .withIssuer(userId)
                    .withExpiresAt(expiresDate)
                    .sign(algorithm);
            return token;
        } catch (JWTCreationException exception) {
            logger.error("创建JWT签名JWTCreationException:{}", exception);
            throw new Exception("创建JWT签名失败,请稍后重试");
        }
    }


    /**
     * 解析JWT分析
     *
     * @param token
     * @return
     */
    public static DecodedJWT decodeJWT(String token) throws Exception {
        try {
            DecodedJWT decode = JWT.decode(token);
            return decode;
        } catch (JWTDecodeException exception) {
            logger.error("解析JWT签名JWTCreationException:{}", exception);
            throw new Exception("解析JWT签名失败,请稍后重试");
        }
    }

    /**
     * 校验token
     * @param token
     * @param userId
     * @return
     * @throws Exception
     */
    public static DecodedJWT validateJWT(String token, String userId) throws Exception {
        try {
            Algorithm algorithm = Algorithm.HMAC256(APP_SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withIssuer(userId)
                    .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
            return jwt;
        } catch (JWTDecodeException exception) {
            logger.error("校验JWT签名JWTCreationException:{}", exception);
            throw new Exception("校验JWT签名失败,请稍后重试");
        }
    }

猜你喜欢

转载自blog.csdn.net/crossroads10/article/details/108329196