JJWT最新版本0.12.x使用指南,实现登陆功能,JwtUtils

JWT简介

JWT(JSON Web Token)令牌登录,是一种用于身份验证的开放标准。它是一个基于JSON格式的安全令牌,主要用于在网络上传输声明或者用户身份信息。JWT通常被用作API的认证方式,以及跨域身份验证。

JWT令牌由三部分组成,分别是头部(Header)、载荷(Payload)和签名(Signature)。

  • Header:记录令牌类型,加密算法

  • Payload:包含声明,声明是有关实体(通常是用户)和其他数据的语句。

    • 已注册声明:这些是一组预定义的声明,这些声明不是必需的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:iss(发行人),exp(到期时间),sub(主题),aud(受众)等。
    • 公共声明:这些可以由使用 JWT 的人随意定义。但为了避免冲突,它们应该在 IANA JSON Web 令牌注册表中定义,或者定义为包含抗冲突命名空间的 URI。
    • 专用声明:这些是创建的自定义声明,用于在同意使用它们的各方之间共享信息,既不是注册声明也不是公共声明。
    注册的声明(建议但不强制使用):
    iss: jwt签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须要大于签发时间
    nbf: 定义在什么时间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
    
  • Signature:签名,防止被篡改。(header+payload+密钥)*签名算法

使用步骤

  1. 导入依赖
<!--JWT令牌-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.12.5</version>
</dependency>

版本可查:https://mvnrepository.com/

  1. 创建JwtUtils工具类(可选)

网上教程大部分是0.9.x版本,最新版本0.12.x将其中的很多方法弃用,这里给出新接口的用法。

public class JwtUtils {

    /**
     * 生成jwt
     * 使用Hs256算法, 私匙使用固定秘钥
     *
     * @param secretKey jwt秘钥
     * @param ttlMillis jwt过期时间(毫秒)
     * @param claims    设置的信息
     * @return
     */
    public static String createJwt(String secretKey, long ttlMillis, Map<String, Object> claims) {
        // 指定签名的时候使用的签名算法,也就是header那部分
//        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成JWT的时间
        long expMillis = System.currentTimeMillis() + ttlMillis;
        Date exp = new Date(expMillis);

        //生成 HMAC 密钥,根据提供的字节数组长度选择适当的 HMAC 算法,并返回相应的 SecretKey 对象。
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(key)
                // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
                .claims(claims)
                // 设置过期时间
                .expiration(exp);
        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param secretKey jwt秘钥 此秘钥一定要保留好在服务端, 不能暴露出去, 否则sign就可以被伪造, 如果对接多个客户端建议改造成多个
     * @param token     加密后的token
     * @return
     */
    public static Claims parseJWT(String secretKey, String token) {

        //生成 HMAC 密钥,根据提供的字节数组长度选择适当的 HMAC 算法,并返回相应的 SecretKey 对象。
        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));

        // 得到DefaultJwtParser
        JwtParser jwtParser = Jwts.parser()
                // 设置签名的秘钥
                .verifyWith(key)
                .build();
        Jws<Claims> jws = jwtParser.parseSignedClaims(token);
        Claims claims = jws.getPayload();
        return claims;
    }
}
  1. 将配置信息写入yml中,注入到JwtProperties
//新建一个JwtProperties类
@Data
@Component
@ConfigurationProperties(prefix = "com.jwt")
public class JwtProperties {

    /**
     * 用户端用户生成jwt令牌相关配置
     */
    private String userSecretKey;
    private long userTtl;
    private String userTokenName;
}

---
//写入yml中
com:
  jwt:
    user-secret-key: lbw
    user-ttl: 7200000
    user-token-name: authentication
  1. 生成jwt令牌
//登陆controller中生成,返回给客户端
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.USER_ID,user.getId());
claims.put(JwtClaimsConstant.USERNAME,user.getUsername());
String token = JwtUtils.createJwt(
    jwtProperties.getUserSecretKey(),
    jwtProperties.getUserTtl(),
    claims
);
  1. 解析jwt令牌
//需要创建一个jwt拦截器,注册到WebMvcConfiguration配置类中
Claims claims = JwtUtils.parseJWT(jwtProperties.getUserSecretKey(), token);
//claims就是在Pyload中存放的用户信息
claims.get("keyname")

JWT两种主要使用方式

  • JWS (JSON Web Signature):

这种方式下,JWT 是签名的,确保消息的完整性和真实性。签名的目的是防止数据被篡改,并验证发送者的身份。常见的签名算法包括 HMAC、RSA 和 ECDSA。

签名的 JWT 由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。格式如下:

Copy Code<header>.<payload>.<signature>

登录功能在一般情况下,不需要在用户端保存敏感信息,也就不用加密处理;但需要保证用户请求不被伪造、篡改,就需要进行数字前面。所以一般用jws实现登录验证。

  • JWE (JSON Web Encryption):

这种方式下,JWT 是加密的,用于保护敏感数据。加密的目的是确保只有授权方能够读取数据内容。常见的加密算法包括 AES 和 RSA。

加密的 JWT 包含五个部分:头部(Header)、加密密钥(Encrypted Key)、初始化向量(Initialization Vector)、密文(Ciphertext)和认证标签(Authentication Tag)。格式如下:

Copy Code<header>.<encryptedKey>.<iv>.<ciphertext>.<tag>

加密的 JWT 对载荷进行加密处理,使得未经授权的一方无法读取载荷内容。

jwt优点

  • 支持跨域访问:cookie是无法跨域的,而token由于没有用到cookie(前提是将token放到请求头中),所以跨域后不会存在信息丢失问题
  • 无状态:token机制在服务端不需要存储session信息,因为token自身包含了所有登录用户的信息,所以可以减轻服务端压力
  • 更适用CDN:可以通过内容分发网络请求服务端的所有资料
  • 更适用于移动端:当客户端是非浏览器平台时,cookie是不被支持的,此时采用token认证方式会简单很多
  • 无需考虑CSRF:由于不再依赖cookie,所以采用token认证方式不会发生CSRF,所以也就无需考虑CSRF的防御

JWT的退出登录

jwt是无状态的,服务端无法在使用过程主动废弃token,只有等到过期时间才会作废。

不过这可以由前端浏览器实现,点退出时用前端代码将Storage中的Token清除,相当于登录退出。

此外,如果你在状态跟踪时,在服务端用缓存存储了其他信息,可以在缓存中查询用户是否存在。如下:

image-20240619154025435

如果没有用缓存存储信息,不建议为了登陆校验额外建立缓存,这相当于服务端会话跟踪,有其相应的缺点。

  • 11
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JWTUtils通常需要依赖于一些第三方库,例如JJWTJava JWT)或Nimbus JOSE + JWT。以下是一个使用JJWT库的示例,演示了如何使用JWTUtils来生成、解析和验证JWT: #### 生成JWT ```java import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; public class JWTUtils { private static final String SECRET_KEY = "my-secret-key"; // 对称加密密钥 public static String generateToken(String subject, long expirationMillis) { return Jwts.builder() .setSubject(subject) .setExpiration(new Date(System.currentTimeMillis() + expirationMillis)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } } ``` 这个方法使用JJWT库的`Jwts`类来创建JWT。`setSubject`方法用于设置JWT的主题,`setExpiration`方法用于设置JWT的过期时间。`signWith`方法用于指定JWT的签名算法和密钥。最后,`compact`方法将JWT转换为紧凑格式的字符串。 #### 解析JWT ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; public class JWTUtils { private static final String SECRET_KEY = "my-secret-key"; // 对称加密密钥 public static Claims parseToken(String token) { Jws<Claims> jws = Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token); return jws.getBody(); } } ``` 这个方法使用JJWT库的`Jwts`类来解析JWT。`setSigningKey`方法用于指定JWT的签名密钥。`parseClaimsJws`方法将JWT解析为`Jws`对象,其中包含JWT的头部、声明和签名。`getBody`方法返回JWT的声明部分。 #### 验证JWT ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; public class JWTUtils { private static final String SECRET_KEY = "my-secret-key"; // 对称加密密钥 public static boolean validateToken(String token) { try { Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token); return true; } catch (Exception e) { return false; } } } ``` 这个方法使用JJWT库的`Jwts`类来验证JWT。`setSigningKey`方法用于指定JWT的签名密钥。如果JWT验证成功,则不会抛出任何异常,该方法将返回`true`。否则,将抛出异常并返回`false`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值