JWT的原理和使用

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT
在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

传统的session认证
http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。
但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来.

基于session认证所显露的问题
Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。
扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。
CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

JWT的构成
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
Header
jwt的头部承载两部分信息:
声明类型,这里是jwt
声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:
{

"alg": "HS256"

}
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分. eyJhbGciOiJIUzI1NiJ9

Payload
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
标准中注册的声明 (建议但不强制使用) :
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:
{

"euid": "GA000001780",
"accountType": "Personal",
"deviceUniqueCode": "Xw7tEIcd5jEDADuW9S5eXKSE",
"accessTokenExpires": 1637949995184,
"accessToken": "1caa2a8e4adb77007c6d97599749db26ba47b14996db8d75f12f9a404ccfe0f5",
"exp": 1639123595,
"jwtExpires": 1639123595184,
"deviceBrand": "HONOR",
"refreshToken": "3cde7a1cf457685d25fe179c853cb022012acd2913d92d7f67748c6d2d3108ab"

}
然后将其进行base64加密,得到JWT的第二部分
eyJldWlkIjoiR0EwMDAwMDE3ODAiLCJhY2NvdW50VHlwZSI6IlBlcnNvbmFsIiwiZGV2aWNlVW5pcXVlQ29kZSI6Ilh3N3RFSWNkNWpFREFEdVc5UzVlWEtTRSIsImFjY2Vzc1Rva2VuRXhwaXJlcyI6MTYzNzk0OTk5NTE4NCwiYWNjZXNzVG9rZW4iOiIxY2FhMmE4ZTRhZGI3NzAwN2M2ZDk3NTk5NzQ5ZGIyNmJhNDdiMTQ5OTZkYjhkNzVmMTJmOWE0MDRjY2ZlMGY1IiwiZXhwIjoxNjM5MTIzNTk1LCJqd3RFeHBpcmVzIjoxNjM5MTIzNTk1MTg0LCJkZXZpY2VCcmFuZCI6IkhPTk9SIiwicmVmcmVzaFRva2VuIjoiM2NkZTdhMWNmNDU3Njg1ZDI1ZmUxNzljODUzY2IwMjIwMTJhY2QyOTEzZDkyZDdmNjc3NDhjNmQyZDMxMDhhYiJ9

Signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

public String sign(String jwtWithoutSignature) {
    byte[] bytesToSign = jwtWithoutSignature.getBytes(US_ASCII);
    byte[] signature = this.signer.sign(bytesToSign);
    return TextCodec.BASE64URL.encode(signature);

}
得到JWT的第三部分:H4JhbO-QRMx9Nq-_H6NZM02MlTEyUaSMRIr8e2iD1WI
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:

image.png

五、JWT优点
因为json的通用性,所以JWT是可以进行跨语言支持的,JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
它不需要在服务端保存会话信息, 所以它易于应用的扩展
安全相关
不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
保护好secret私钥,该私钥非常重要。
六、JWT使用示例

在pom.xml文件下添加依赖

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.6.0</version>
    </dependency>
</dependencies>

示例代码:

import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;

/**
 * JWTUtils工具类,生成jwt和解析jwt
 * JSON WEB TOKEN 结构组成:
 * (1)Header(头部):包含加密算法,通常直接使用 HMAC SHA256
 * (2)Payload(负载):存放有效信息,比如消息体、签发者、过期时间、签发时间等
 * (3)Signature(签名):由header(base64后的)+payload(base64后的)+secret(秘钥)三部分组合,然后通过head中声明的算法进行加密
 *
 */
public class JwtUtil {

    /**
     * 由字符串生成加密key
     *
     * @return
     */
    public static SecretKey generalKey(String stringKey) {
        byte[] encodedKey = Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 创建jwt
     * @param claims 负载
     * @param expirationDate  生成jwt的有效期,单位秒
     * @return jwt token
     * @throws Exception
     */
    public static String createJWT(Map<String,Object> claims, long expirationDate,String secretKey) throws Exception {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey key = generalKey(secretKey);
        JwtBuilder builder = Jwts.builder().setClaims(claims)
                .signWith(signatureAlgorithm, key);
        if (expirationDate >= 0) {
            long nowMillis = System.currentTimeMillis();
            long expMillis = nowMillis + expirationDate*1000;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * 解密jwt,获取实体
     * @param jwt
     */
    public static Claims parseJWT(String jwt,String secretKey) throws ExpiredJwtException, UnsupportedJwtException,
            MalformedJwtException, SignatureException, IllegalArgumentException {
        SecretKey key = generalKey(secretKey);
        Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt).getBody();
        return claims;
    }

}
相关文章
|
7月前
|
存储 JSON 算法
无懈可击的身份验证:深入了解JWT的工作原理
无懈可击的身份验证:深入了解JWT的工作原理
1034 0
|
JSON 安全 Java
JWT的原理及实际使用
JWT的原理及实际使用
146 0
|
4月前
|
安全 Nacos 数据安全/隐私保护
【技术干货】破解Nacos安全隐患:连接用户名与密码明文传输!掌握HTTPS、JWT与OAuth2.0加密秘籍,打造坚不可摧的微服务注册与配置中心!从原理到实践,全方位解析如何构建安全防护体系,让您从此告别数据泄露风险!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心,但其连接用户名和密码的明文传输成为安全隐患。本文探讨加密策略提升安全性。首先介绍明文传输风险,随后对比三种加密方案:HTTPS简化数据保护;JWT令牌减少凭证传输,适配分布式环境;OAuth2.0增强安全,支持多授权模式。每种方案各有千秋,开发者需根据具体需求选择最佳实践,确保服务安全稳定运行。
392 0
|
6月前
|
存储 算法 Java
闲鱼面试:说说JWT工作原理?
闲鱼面试:说说JWT工作原理?
59 0
闲鱼面试:说说JWT工作原理?
|
5月前
|
存储 JSON 算法
JWT原理与在身份验证中的应用
JWT原理与在身份验证中的应用
|
存储 JSON 算法
JWT的原理及实际应用
JWT的原理及实际应用
188 1
|
7月前
|
存储 JSON 算法
net core jwt的基本原理和实现
这篇文章介绍了.NET Core中JWT(JSON Web Token)的基本原理和实现。JWT是一种用于安全传输信息的开放标准,由头部、负载和签名三部分组成。在.NET Core中实现JWT,需要安装`Microsoft.AspNetCore.Authentication.JwtBearer`包,然后在`Startup.cs`配置JWT认证服务,包括设置密钥和验证参数。生成JWT令牌后,客户端存储并将其包含在请求头中发送给服务器进行验证和授权。JWT提供了一种无需服务器存储会话数据的安全身份验证和授权机制。
|
前端开发
什么是JWT?深入理解JWT从原理到应用(下)
什么是JWT?深入理解JWT从原理到应用(下)
116 0
|
存储 JSON 前端开发
了解什么是JWT的原理及实际应用
了解什么是JWT的原理及实际应用
1356 0
|
7月前
|
JSON 安全 网络安全
超详细的用户认证、权限、安全原理详解(认证、权限、JWT、RFC 7235、HTTPS、HSTS、PC端、服务端、移动端、第三方认证等等)
超详细的用户认证、权限、安全原理详解(认证、权限、JWT、RFC 7235、HTTPS、HSTS、PC端、服务端、移动端、第三方认证等等)
1112 0

热门文章

最新文章