JWT学习笔记

了解 JWT Token 释义及使用 | Authing 文档

JSON Web Token Introduction - jwt.io

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

1. 认证

传统的Session认证方式需要在服务器端存储用户登录信息,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。基于Token的认证方式不需要在服务端去保留用户的认证信息或者会话信息。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

2. JWT的结构

它采用缩写的形式,包含三个部分,由.分割,包括以下三个部分

  • Header------头部
  • Payload------有效荷载
  • Signature------签名

因此JWT呈现为这种形式:

xxxxx.yyyyy.zzzzz

2.1. Header

头部包含两个部分:(1)token的类型,即JWT;(2)使用的签名算法,如HMAC、SHA256或RSA

例如:

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

2.2. Payload

该部分包含一些实体和数据的声明,如用户等,包括已注册声明、公开声明、私有声明三类。

例如:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

2.3. Signature

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

3. 使用

jjwt10:GitHub - jwtk/jjwt: Java JWT: JSON Web Token for Java and Android

目前jjwt10以上版本和jjwt9使用方法不同,好像使用jjwt9还是偏多一些。

jjwt9:jjwt 0.9.1 javadoc (io.jsonwebtoken)

以下代码是从mall项目中学习的JWT的工具类,一般可作为模板使用,主要提供了生成token和解析token的API,使用的是jjwt9

@Component
public class JwtTokenUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenUtil.class);

    //sub: subject,主体,即登录的主体,一般是用户名
    private static final String CLAIM_KEY_USERNAME = "sub";

    //created表示创建时间
    private static final String CLAIM_KEY_CREATED = "created";
    @Value("${jwt.secret}")
    private String secret;
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 根据负载生成JWT的token
     * @param claims 声明,即JWT中的payload部分
     * @return token:String
     */
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()   //生成一个DefaultJwtBuilder类实例
                .setClaims(claims)      //设置该DefaultJwtBuilder类实例的claims字段
                .setExpiration(generateExpirationDate())    //设置过期时间
                .signWith(SignatureAlgorithm.HS512, secret) //设置签名算法、密钥
                .compact();     //调用compact函数才能生成JWT
    }

    /**
     * 从token中获取JWT中的负载
     * @param token
     * @return Claims类实例
     */
    private Claims getClaimsFromToken(String token) {
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.info("JWT格式验证失败:{}",token);
        }
        return claims;
    }

    /**
     * 根据expiration生成token的过期时间
     * @return Date
     */
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    /**
     * 从token中获取登录用户名
     */
    public String getUserNameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username =  claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }

    /**
     * 验证token是否还有效
     *
     * @param token       客户端传入的token
     * @param userDetails 从数据库中查询出来的用户信息
     */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUserNameFromToken(token);
        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
    }

    /**
     * 判断token是否已经失效
     */
    private boolean isTokenExpired(String token) {
        Date expiredDate = getExpiredDateFromToken(token);
        return expiredDate.before(new Date());
    }

    /**
     * 从token中获取过期时间
     */
    private Date getExpiredDateFromToken(String token) {
        Claims claims = getClaimsFromToken(token);
        return claims.getExpiration();
    }

    /**
     * 根据用户信息生成token
     * @param userDetails UserDetails类实例
     * @return token
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}
相关推荐
赢乐7 天前
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单
中间件·node.js·express·jwt·session·cors·单点登录sso
String NUll9 天前
基于 JWT 进行身份验证
jwt
VinciYan24 天前
开源网关Apache APISIX启用JWT身份验证
docker·微服务·apache·jwt·apisix·开源网关
楠枬24 天前
JWT令牌技术
服务器·spring·jwt
Feather Duster1 个月前
.net 下的身份认证与授权的实现
.net·认证·jwt·授权·单点登录·sso
Geek_H1 个月前
博客星球大冒险:用Spring Boot和JWT打造你的数字王国
java·后端·spring cloud·微服务·https·jwt·cors
伊织code2 个月前
OAuth2、JWT
jwt·oauth2
象话2 个月前
JWT原理解析
jwt·jwt原理·jwt的特点
一见已难忘2 个月前
Flask中的JWT认证构建安全的用户身份验证系统
python·安全·flask·jwt·json的开放标准
W Y2 个月前
【架构-12】JWT和Token
架构·jwt·token