使用JWT生成Token进行接口鉴权实现方法

利用JWT进行鉴权的思路

  1. 用户发起登录请求。
  2. 服务器使用私钥创建一个jwt字符串,作为token;
  3. 服务器将这个token返回给浏览器;
  4. 在后续请求中,token作为请求头的内容,发给服务端。
  5. 服务端拿到token之后进行解密,正确解密表示此次请求合法,验证通过;解密失败说明Token无效或者已过期
  6. 返回响应的资源给浏览器
    在这里插入图片描述

JWT介绍

什么是JWT

JSON Web令牌(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,以JSON对象的形式在通信双方之间安全地传输信息。由于该信息是数字签名的,因此可以对其进行验证和信任。jwt可以使用散列消息鉴别码(使用HMAC算法),也可以使用RSA或ECDSA公钥/私钥对签名。

应用场景

  • 授权: 这是使用JWT最常见的场景。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录SSO是目前JWT广泛使用的一个特性,因为它的开销很小,而且可以轻松地跨不同的领域使用。
  • 信息交换:JSON Web Tokens 是在各方之间安全地传输信息的一种好方法。因为JWT可以签名(例如,使用公钥/私钥对),所以可以确定发送方就是他们所说的那个人。此外,由于使用头和有效负载计算签名,您还可以验证内容没有被篡改

优点

  • 简洁(Compact): 可以通过GET参数、POST参数、HTTP header发送,因为数据量小,传输速度也很快
  • 自包含(Self-contained):负载中包含了所有用户所需要的信息,避免了多次查询数据库
  • 因为Token是以JSON加密的形式保存在客户端的,所以JWT是跨语言的,原则上任何web形式都支持。
  • 不需要在服务端保存会话信息,特别适用于分布式微服务。

JWT的结构

JWT是由三段信息构成的,将这三段信息文本用**.**连接一起就构成了JWT字符串。
JWT通常长成这样:xxxx.yyyy.zzzzz
实际示例如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiLlvKDkuIkiLCJleHAiOjE2MzI0NzQxMzQsInVzZXJuYW1lIjoi5byg5LiJIn0.r1UipPk6_69r5Cd7kPoz6rM4NDKDF37su0YOWVGOZ6U

JWT包含了三部分:

  • Header 头部: 通常由两部分组成:令牌的类型,即JWT,以及使用的签名算法,如HMAC SHA256或RSA。
  • Payload 负载: 有效负载,通信双方要交换的内容
  • Signature 签名/签证

在这里插入图片描述

Header

通常由两部分组成:令牌的类型,即JWT,以及使用的签名算法,如HMAC SHA256或RSA。

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

加密算法是单向函数散列算法,常见的有MD5、SHA、HAMC。

  • *MD5(message-digest algorithm 5)信息-摘要算法:广泛用于加密和解密技术,常用于文件校验。不管文件多大,经过MD5后都能生成唯一的MD5值
  • SHA (Secure Hash Algorithm)安全散列算法,数字签名等密码学应用中重要的工具,安全性高于MD5
  • HMAC (Hash Message Authentication Code)散列消息鉴别码,基于密钥的Hash算法的认证协议。用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。常用于接口签名验证

Payload

有效负载就是存放通信双方要交换的内容的地方
有效信息包含三个部分

  • Registered claims 标准中注册的声明
  • Public claims 公共的声明
  • Private claims 私有的声明

标准中注册的声明:这些是一组预定义的声明,不是强制性的,但推荐使用这些声明,以提供一组有用的、可互操作的声明。

  • iss: jwt签发者
  • sub: 面向的用户(jwt所面向的用户)
  • aud: 接收jwt的一方
  • exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

公共的声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息. 但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

Signature

jwt的第三部分是一个签证信息
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和进行验证,所以需要保护好。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

使用的工具类

导入依赖

		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.11.0</version>
		</dependency>

工具类源码

public class JwtUtil {
	public static void main(String[] args) {
        String secret = "123456";
        String username = "张三";
        String token = sign(username, secret);
        printMsg("token:%s", token);
        printMsg("username:%s", getUsername(token));
        printMsg("verify:%s", verify(token, username, secret));
    }

    private static void printMsg(String template, Object... args) {
        System.out.println(String.format(template, args));
    }
    
    public static final long EXPIRE_TIME = 1800000L;

    public JwtUtil() {
    }

    public static boolean verify(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            verifier.verify(token);
            return true;
        } catch (Exception var6) {
            return false;
        }
    }

    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException var2) {
            return null;
        }
    }

    public static String sign(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + 1800000L);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
    }

    public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException {
        String accessToken= request.getParameter("token");
        if (accessToken== null) {
            accessToken= request.getHeader("X-Access-Token");
        }
        String username = getUsername(accessToken);
        if (oConvertUtils.isEmpty(username)) {
            throw new JeecgBootException("未获取到用户");
        } else {
            return username;
        }
    }
}

参考

JWT官网
JWT(Java版)的github

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

enjoy编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值