关于Token (令牌)
说起令牌,仿佛回到了封建时代,一掏出令牌,其他人都知道你是什么身份了。
而在web系统中,前后端的业务交互也往往需要附带身份数据,先姑且把这个数据统称为 Token (令牌) 。
面向有状态HTTP请求:
Token实际上是由cookies+session 实现
服务端session存储了每个客户端的状态(比如用户登录后,服务端为这个客户端存储的session中就有了用户标识数据)。
session存储时为每一个客户端分配了sessionId
前端cookies存储了sessionId,保证同一个客户端一段时间内请求后端,使用同一个sessionId
以上实现了后端在一定时间内都"认识“这个客户端
面向无状态HTTP请求:
服务端不再存储每个请求客户端的状态,客户端也不再依赖cookies机制
客户端每次请求中自带身份标识
服务端根据客户端请求中的token参数来验证或者提取用户数据
可以有很多种实现,系统中定义一个token,或者使用JWT等
微服务架构下token授权与验证流程
我画了个微服务架构下tokenn授权与验证的流程。
其中我这里拟支持3种Token形式:
1、MD5 Token : 属于系统内部自定义一种Token规则,我这里只是简单地将用户的几个字段进行了拼接MD5,用户调用接口登录成功后,就把token生成并颁发给客户端。
验证时需要在数据库中查询token颁发记录,从而获取对应的用户信息
2、Jwt : JSON Web Tokens,一种便于分布式架构中传输Token的一种规范,跟上述的Token串不同的是,它可以直接把用户信息也打包进去。所以这里面常常存的不只是一个令牌,而是直接包含了业务接口所需的用户信息、以及业务数据。Jwt默认不加密,只是进行签名验证,防止篡改,但是里面存放的数据是可见的(通过Base64URL 解码)。
验证时直接从Jwt中提取登录用户信息,不需要查询数据库
3、Jwt+ AES : 是基于第二种方案进行了AES对称加密,这样在传输过程中,里面的数据是不可见的。
验证时进行AES解密出原Jwt,直接从Jwt中提取登录用户信息,不需要查询数据库
主要代码
完整代码:https://gitee.com/zhaojunfu2014/springcloud-learn-tokens
项目基于:springboot,mybatis plus
数据库:mysql
目的:实现 流程图的 2,3 6,7 节点 ,接口定义如下:
package com.jfcloud.all.user.service;
import com.jfcloud.all.user.domain.param.GrantParams;
/**
* 微服务鉴权服务
* @author zhaojunfu
*
*/
public interface TokenService {
/**
* 认证接口<br>
* 认证通过后返回token对象
* @param params 参数列表
* @return
* @throws Exception
*/
Object grant(GrantParams params) throws Exception;
/**
* 验证token有效性,并提取用户信息
* @param token
* @return
*/
Object validateAndGet(Object token);
}
自定义MD5 Token 实现
数据库表设计
jfcloud_user:用户表,模拟业务系统中需要登录的用户,登录后可用token验证后换取此用户信息
jfcloud_user_token: token表,为用户颁发token的记录
CREATE TABLE `jfcloud_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名',
`realname` varchar(100) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '昵称',
`password` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
`account` decimal(20,2) DEFAULT NULL COMMENT '账户余额',
`order_num` bigint(20) DEFAULT NULL COMMENT '下单数量',
`buy_num` bigint(20) DEFAULT NULL COMMENT '购买产品数',
`buy_amount` decimal(20,2) DEFAULT NULL COMMENT '购买金额',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`is_delete` int(1) DEFAULT '0' COMMENT '逻辑删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `jfcloud_user_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
`token` varchar(200) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户登录token',
`status` int(1) DEFAULT '1' COMMENT '状态 0:无效 1:有效',
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`is_delete` int(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=u