token验证的机理和简单实现

摘要:token验证,机制实现

一、cookie验证和token验证的比较

    cookie验证的机制是通过在客户端生成cookie,在服务器端生成session,然后每次请求时通过核对前端传来的cookie和服务器端session是否一致来管理用户的状态。当我们关闭浏览器的时候session会被释放,而cookie也可以自定义失效时间使其在一定时间内失效。

    token的验证机制放弃了session,为用户生成包含各类信息的一个集合,将其编码为一个令牌(token),将这个令牌发给前端,前端每次需要验证身份时携带令牌,服务器检查令牌的合法性以验证身份。简化了服务器的存储,但是要比session+cookie的验证方式更加消耗计算。是一种以时间换空间的方式。


相较于cookie验证的几点好处:

  1. 支持跨域:cookie是不支持跨域的,token则可以做到。这一点对于我们项目深有感触,前端和后台是分离开发和测试,前端的测试常常需要跨域测试,没有token之前总是统一汇总测试,很麻烦,也想当拖节奏。
  2. 无状态:因为cookie验证是依赖于session的状态的,而token则完全不用在session中保存任何数据,所以可以做到无状态,只要有token并且合法就可以。

   二、token的组成和简单实现

token主要有三个部分组成:头部,载荷,签名。

头部和载荷使用的是base64编码的,签名则是使用的HS256。当时不是很明白这个HS256,实际上就是HMAC using SHA-256。一种带密钥的加密。base64可以利用java有自带的工具Base64Encoder。

具体参考下面的博客:

https://blog.csdn.net/weixin_39800144/article/details/78853323

我们通过一个类来实现这个token的功能

此处使用了导入了Jackson的jar包,方便将对象转化为json,不然需要手动的转化。

import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.thoughtworks.xstream.core.util.Base64Encoder;
import com.zhiku.util.Data;

public class Token {
	
	//JWT的header,实际工作中从配置文件中获得
	public static String Header = "{\"typ\": \"JWT\",\"alg\": \"HS256\"}";
	//密钥
	public static String SECRET_KEY = "secret";
	//base64编码工具
	public static Base64Encoder be = new Base64Encoder();
	
	public static String getToken(Data message) throws Exception{
		String header = setHeader();
		String payload = setPayload(message);
		String signature = setSignature(header + "." + payload);
		return header + "." + payload + "." + signature;
		
	}

	/**
	 * 设置JWT的荷载payload,荷载中包含主要的信息
	 * @param payload 一个可以格式化为json的对象
	 * @return
	 * @throws Exception
	 */
	public static String setPayload(Object payload) throws Exception{
		String base64_payload = om.writeValueAsString(payload);
		return be.encode(base64_payload.getBytes());
	}
	
	public static Object getPayload(String base64_payload) throws Exception{
		byte[] h = be.decode(base64_payload);
		return om.readValue(h, Object.class);
	}
	
	/**
	 * 设置header
	 * 获取已有的header,然后生成base64编码
	 * @return
	 */
	public static String setHeader(){
		return be.encode(Header.getBytes());
	}
	
	/**
	 * 解析header
	 * @param base64_Header	base64编码的header部分
	 * @return	返回解码后的header,以一个data的形式返回对应的json
	 * @throws Exception	在将json转变为data对象时可能出现异常
	 */
	public static Object getHeader(String base64_Header) throws Exception{
		byte[] h = be.decode(base64_Header);
		return om.readValue(h, Object.class);
	}
	
	/**
	 * 将header和payload使用HS256加密
	 * 然后对加密信息进行base64编码
	 * 生成JWT的签名
	 * @param message	header.payload
	 * @return	JWT的签名
	 * @throws Exception
	 */
	public static String setSignature(String message) throws Exception{
		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
	    SecretKeySpec secret_key = new SecretKeySpec(SECRET_KEY.getBytes(), "HmacSHA256");
	    sha256_HMAC.init(secret_key);

	    String hash = be.encode(sha256_HMAC.doFinal(message.getBytes()));
	    return hash;
	}
	
	/**
	 * 验证token的正确性
	 * @param token	待验证token
	 * @return	token是否正确
	 */
	public static boolean testSign(String token){
		boolean equal = false;
		String fore_message = token.substring(0,token.lastIndexOf('.'));
		String sign = token.substring(token.lastIndexOf('.')+1);
		try{
			if(sign.equals(setSignature(fore_message))){
				equal = true;
			}else{
				equal = false;
			}
		}catch(Exception e){
			equal = false;
		}
		return equal;
	}
	
	
}

注意:在经过base64转码之后有些时候会包含“+”,在前端传给后台的时候,“+”会变成“ ”(加号变成了空格)。这个时候就会影响token的验证,可以使用字符串将其替换。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值