Token介绍

Token 令牌

Token是什么?

Token在web程序中,它是服务端生成的一串字符串,作为客户端进行请求的一个标识

为什么要用Token,它能解决什么问题?
  1. Token 完全由应用管理,所以它可以避开同源策略,即可以跨域访问

    应用场景:单点登录(SSO)

    单点登录的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统

  2. Token 可以避免 CSRF 攻击

  3. Token 可以是无状态的,可以在多个服务间共享

怎么使用Token?

在web程序中,Token应用很广泛,这里只介绍用于前后端分离技术。

token经常作为一种校验的标识,自身也能携带一些信息,用于网络通信之间。

Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。

简单token的组成;uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token的前几位以哈希算法压缩成的一定长度的十六进制字符串。为防止token泄露)。

使用token机制的身份验证方法,在服务器端不需要存储用户的登录记录。大概的流程:

客户端使用用户名和密码请求登录。服务端收到请求,验证用户名和密码。验证成功后,服务端会生成一个token,然后把这个token发送给客户端。客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。客户端每次向服务端发送请求的时候都需要带上服务端发给的token。服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。

JSON Web Token (JWT)

JWT时目前最流行的跨域身份验证解决方案

什么是JWT?

JSON Web Token(JWT)是一个开放标准RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间作为JSON对象安全地传输信息。

为什么要使用JWT?
  • JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范;
  • JWT作为一个开放的标准(RFC 7519)定义了一种简洁的,自包含的方法用于通信双方之间以JSON对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的;
  • JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名;
怎么使用JWT?

要了解怎么使用JWT,先了解它的结构

JWT的组成

JWT组成格式类似:xxxx.xxxx.xxxx的字符串,这里JWT的官网(https://jwt.io/)给出了JWT生成与验证的工具。

JWT主要由三个部分组成:头部(HEADER),载荷(PAYLOAD),签证(SIGNATURE)。

头部(HEADER)

HEADER主要为了描述该JWT的最基本信息,主要包含两个部分:声明类型和声明加密算法(通常直接使用HMAC,SHA256)。

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

有效载荷(PAYLOAD)

有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。

  • iss:发行人

  • exp:到期时间

  • sub:主题

  • aud:用户

  • nbf:在此之前不可用

  • iat:发布时间

  • jti:JWT ID用于标识该JWT

除了以上默认字段外,也可以添加自定义字段。

{
  "sub": "1234567890",
  "name": "chongchong",
  "admin": true
}

签名(SIGNATURE)

JWT的第三部分是一个签名信息,这个签名信息主要由三个部分组成:Header(BASE64后),Payload(BASE64后),secret。

首先这个部分需要BASE64加密后的header和payload,然后使用进行连接组成的字符串,然后通过header中指定的加密方式,进行加盐值secret组合加密,然后就构成了JWT的第三部分。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
代码实现
  1. 添加Maven依赖
	<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.1.0</version>
  </dependency>
  1. 编写工具类
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author LK
 * @date 2019/8/12 17:26
 */
public class JwtUtil {

    /**
     * 加密算法中加的盐
     */
    private static final String SECRET = "9a96349e";

    /**
     * 用户,发布人
     */
    private static String ISSUER = "sys_user";

    /**
     * 生成token
     * @param claims 传入参数
     * @param IssuedAtDatePoint  发布的时间点
     * @return String
     */
    public static String genToken(Map<String, String> claims, Date IssuedAtDatePoint){

      String token;
        try {
            //使用HMAC256进行加密
            Algorithm algorithm = Algorithm.HMAC256(SECRET);

            //创建jwt,添加发行人,发布的时间点
            JWTCreator.Builder builder = JWT.create()
              			.withIssuer(ISSUER)
                    .withIssuedAt(IssuedAtDatePoint);

            //传入参数
            claims.forEach((key,value)-> {
                builder.withClaim(key, value);
            });

            //签名加密
            token = builder.sign(algorithm);
        } catch (IllegalArgumentException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return token;
    }

    /**
     * 解密jwt
     * @param token token
     * @return Map
     * @throws RuntimeException 运行时异常
     */
    public static Map<String,String> verifyToken(String token) throws RuntimeException{
        Algorithm algorithm = null;
        try {
            //使用HMAC256进行加密
            algorithm = Algorithm.HMAC256(SECRET);
        } catch (IllegalArgumentException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

        //解密
        JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUER).build();
        DecodedJWT jwt =  verifier.verify(token);
        Map<String, Claim> map = jwt.getClaims();
        Map<String, String> resultMap = new HashMap<>();
        map.forEach((k,v) -> resultMap.put(k, v.asString()));
        return resultMap;
    }
}

  1. 测试代码
public static void main(String[] args) {
      Map<String,String> map = new HashMap<>();
      map.put("name","张三");
      map.put("sex","男");
      String token = JwtUtil.genToken(map,new Date());
      System.out.println(token);

      map = JwtUtil.verifyToken(token);
      for (Map.Entry<String, String> entry : map.entrySet()) {
          System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
      }
  }
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值