JSON Web令牌(JWT)

Token

概述

Token 是服务端生成的一串字符串,以作为客户端进行请求的一个令牌,当第一次登录后,服务器生成一个 Token 便将此 Token 返回给客户端,以后客户端只需带上这个 Token 前来请求数据即可,无需再次带上用户名和密码。

优势

  • 无状态、可扩展

    • 在客户端存储的Tokens是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。tokens自己hold住了用户的验证信息。
  • Tokens能够创建与其它程序共享权限的程序。

  • 跨域

  • 安全

    • 请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储tokencookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。
  • Token 设置过期时间

JWT

概述

官网:JSON Web Tokens - jwt.io

GitHub:https://github.com/auth0/java-jwt

API:java-jwt 4.0.0-beta.0 javadoc (com.auth0)

JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地将信息作为 JSON 对象传输。 由于此信息是经过数字签名的,因此可以被验证和信任。 可以使用秘钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公用/专用密钥对对 JWT 进行签名。

在前后端或者服务器进行交互的过程中,通过 JSON 形式作为 Web 应用中的令牌,以完成数据传输、加密、签名等相关处理操作。

JWT 认证流程

  1. 首先,前端通过 Web 表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个 HTTP POST 请求。建议的方式是通过 SSL 加密的传输(https协议),从而避免敏感信息被嗅探。
  2. 后端核对用户名和密码成功后,将用户的 id 等其他信息作为 JWT Payload (载荷),将其与头部分别进行 Base64 编码拼接后再生成一个签名,形成一个 JWT(Token)。形成的 JWT 就是一个形同 111.ZzZz.xxx 的字符串。
  3. 后端将 JWT 字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在 localStorage 或 sessionStorage 上,退出登录时前端删除保存的 JWT 即可。
  4. 前端在每次请求时将 JWT 放入 HTTP Header 中的 Authorization 位。(解决XSS和XSRF问题)
  5. 后端检查是否存在,如存在验证 JWT 的有效性。例如,检查签名是否正确;检查 Token 是否过期;检查 Token 的接收方是否是自己(可选)。
  6. 验证通过后后端使用 JWT 中包含的用户信息进行其他逻辑操作,返回相应结果。

JWT 的优势

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

JWT 的组成【重点】

JWT 有3个组成部分,每个部分之间用 . 进行分隔

  • Header
  • Payload
  • Signature

格式为

xxxxx.yyyyy.zzzzz

1、头部(header) 声明类型以及加密算法,例如 HMAC、SHA256或 RSA。

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

2、载荷(payload) 携带一些用户身份信息,用户id,颁发机构,颁发时间,过期时间等。用Base64进行了处理。这一段其实是明文,所以一定不要放敏感信息。例如

{"id": 200, "username": "易烊千玺"}

3、签证(signature) 签名信息,使用了自定义的盐然后加密后的结果,目的就是为了保证签名的信息没有被别人改过,这个一般是让服务器验证的。

JWT 入门

1、pom.xml文件导入对应的依赖

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

2、测试代码

public class JwtTest {
    // 通过JWT获取token
    @Test
    public void createToken() {
        HashMap<String, Object> header = new HashMap<>();
        header.put("alg", "HS256");
        header.put("typ", "JWT");

        Calendar expireTime = Calendar.getInstance();

        expireTime.add(Calendar.MINUTE, 30);

        // 创建一个Token
        String token = JWT.create().
                        // 头部
                        withHeader(header).
                        // 载荷
                        withClaim("username", "易烊千玺").
                        withClaim("id", 1).
                        withExpiresAt(expireTime.getTime()).
                        // 签名(盐)
                        sign(Algorithm.HMAC256("ABC8D!EFG"));

        System.out.println(token);
    }

    // 验证JWT的token
    @Test
    public void verifyToken() {
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("ABC8D!EFG")).build();

        DecodedJWT verify = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjE4MTM4NzY0LCJ1c2VybmFtZSI6IuaYk-eDiuWNg-eOuiJ9.IhMvu1CPUVd94rPTu6HNQTGP_fBTOaJaAofD7WTDFwo");

        System.out.println("token头:" + verify.getHeader());
        System.out.println("token载荷:" + verify.getPayload());
        System.out.println("token签名:" + verify.getSignature());
        System.out.println("id:" + verify.getClaim("id").asInt());
        System.out.println("username:" + verify.getClaim("username").asString());
        System.out.println("过期时间:" + verify.getExpiresAt());

    }
}

JWT 工具类

/**
 * JWT工具类
 */
public class JwtUtils {
    // token头算法
    private static final String ALG = "HS256";
    // token头类型
    private static final String TYP = "JWT";
    // token签名算法
    private static final Algorithm ALGORITHM;
    // token头
    private static final HashMap<String, Object> HEADER = new HashMap<>();
    // token签名
    private static final String SIGN = "QwErTyUi";

    // 静态代码块加载token头以及token签名算法
    static {
        HEADER.put("alg", ALG);
        HEADER.put("typ", TYP);
        ALGORITHM = Algorithm.HMAC256(SIGN);
    }

    /**
     * 获取Token
     *
     * @param claim 载荷
     * @param expireTime 过期时间,单位:分钟
     * @return token
     */
    public static String getToken(Map<String, Object> claim, Integer expireTime) {
        // 返回创建的token
        return JWT.create().
                // 设置头
          
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值