⭐️ 在做微信小程序项目的时候,需要在 Java 后台暂时缓存 openid,以获取用户身份(openid 是公众号用户的唯一标识)
⭐️ 这操作让我想到了曾经做的项目的【登录】功能
💦 登录(客户端身份认证)有两种实现思路:
【1】基于 Cookie、Session
🌸 执行流程:
① 客户端:发送用户名和密码
② 服务器端:验证客户端发送的用户名和密码。验证成功后,创建并保留一个跟客户端相关联的 Session(把客户端信息缓存到 Session 中),返回 Session_ID 给客户端
③ 客户端:将 Session_ID 保存到 Cookie 中
④ 客户端:后续的请求都带上包含了 Session_ID 的 Cookie
⑤ 服务器:通过验证 Cookie 中的 Session_ID 确认用户身份
🌸 该方案的优点:
服务器、客户端基本自动完成一系列的流程,不用编程太多额外的代码
🌸 该方案的确定
在分布式架构下,需解决 Session 共享问题(分布式架构下 Session 默认无法共享)
不支持非浏览器环境(没有 Cookie 机制的环境,如:微信小程序)
【2】 基于 token
🌸 执行流程:
① 客户端:发送用户名和密码
② 服务器端:验证客户端发送的用户名和密码。验证成功后,生成一个跟客户端相关的 token,返回 token 给客户端
③ 客户端:存储 token 到本地
④ 客户端:后续的请求都带上 token
⑤ 服务器:通过 验证 token 确认用户身份
🌸 该方案优点:
支持分布式架构、支持非浏览器环境
🌸 该方案缺点:
需要客户端手动存储和发送 token
有些 token 会 比 Session_ID 大,需要消耗更多的流量
有些 token 方案默认无法在服务器端主动销毁 token
💦 方案一通过 Session【
request.getSession().setAttribute(k, v)
】缓存用户信息在服务器端。可通过 Session 的 key 把用户信息给移除掉,实现【让用户下线的功能】
💦 方案二可使用 Session 缓存用户信息(不推荐,在非浏览器环境或前后端分离的时候 Session 是不共享的)。最佳实践使用 Redis 环境用户信息,用 Redis 缓存用户信息一般是分布式架构的时候。单体应用的使用可使用简单的 Ehcache 框架。
下面是对 Ehcache 框架的基本介绍和基本使用(包括工具类的封装和配置文件解释)
🍀 EhCache 是一个纯 Java 的缓存框架。具有快速、精干等特点,是 Hibernate(一个持久层框架,类似 MyBatis) 中默认的 CacheProvider
🍀 EhCache 是一款简单易用的缓存框架。它支持 3 层缓存:Heap(JVM 的堆内存)、Off-Heap(堆外内存)、Disk(磁盘)。【Off-Heap 和 Disk 要求对象支持序列化和反序列化】
🍀 它简单易用,没有 Java 的 Session 在非浏览器环境或前后端分离时候的 Session 不共享情况;没有 Redis 框架的庞大(Redis 太高级了,常被使用于分布式架构),是单体应用中最好的缓存者。
https://www.ehcache.org/documentation/3.8/getting-started.html
<dependency>
<groupId>org.ehcachegroupId>
<artifactId>ehcacheartifactId>
dependency>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3
http://www.ehcache.org/schema/ehcache-core.xsd">
<persistence directory="F:/ehcache"/>
<cache-template name="common">
<key-type>java.lang.Objectkey-type>
<value-type>java.lang.Objectvalue-type>
<resources>
<heap>1000heap>
resources>
cache-template>
<cache alias="token" uses-template="common">
<expiry>
<tti unit="days">7tti>
expiry>
cache>
<cache alias="openid" uses-template="common">
<expiry>
<ttl unit="days">1ttl>
expiry>
cache>
<cache alias="default" uses-template="common">
<expiry>
<none/>
expiry>
cache>
config>
🌿 【cache】标签用于创建不同的缓存空间,不同的缓存空间缓存不同类型的数据。同一个缓存空间缓存的数据是相似的
🌿 【expiry】标签用于设置缓存的过期时间
🌿 【ttl】指定时间后缓存过期
🌿 【tti】指定时间内未使用缓存过期
需在工具类中读取配置文件 cache.xml,并编写【增删改】缓存数据的代码
/**
* 缓存工具类
*/
@SuppressWarnings("all")
public class EhCaches {
// 缓存管理器(只用初始化一次)
private static final CacheManager MGR;
private static final Cache<Object, Object> DEFAULT_CACHE;
private static final Cache<Object, Object> TOKEN_CACHE;
private static final Cache<Object, Object> OPENID_CACHE;
static {
/* 初始化缓存管理器 */
// 读取配置文件
URL url = Ehcache.class.getClassLoader().getResource("ehcache.xml");
assert url != null;
XmlConfiguration xmlConfiguration = new XmlConfiguration(url);
MGR = CacheManagerBuilder.newCacheManager(xmlConfiguration);
MGR.init();
/* 拿到缓存对象 */
DEFAULT_CACHE = MGR.getCache("default", Object.class, Object.class);
TOKEN_CACHE = MGR.getCache("token", Object.class, Object.class);
OPENID_CACHE = MGR.getCache("openid", Object.class, Object.class);
}
/* 增 */
public static void defaultPut(Object key, Object val) {
DEFAULT_CACHE.put(key, val);
}
public static void openidPut(Object key, Object val) {
OPENID_CACHE.put(key, val);
}
public static void tokenPut(Object key, Object val) {
TOKEN_CACHE.put(key, val);
}
/* 删 */
public static void defaultRemove(Object key) {
DEFAULT_CACHE.remove(key);
}
public static void openidRemove(Object key) {
OPENID_CACHE.remove(key);
}
public static void tokenRemove(Object key) {
TOKEN_CACHE.remove(key);
}
/* 查 */
public static <T> T defaultGet(Object key) {
return (T) DEFAULT_CACHE.get(key);
}
public static <T> T openidGet(Object key) {
return (T) OPENID_CACHE.get(key);
}
public static <T> T tokenGet(Object key) {
return (T) TOKEN_CACHE.get(key);
}
/* 清空所有 */
public static void defaultClear() {
DEFAULT_CACHE.clear();
}
public static void openidClear() {
OPENID_CACHE.clear();
}
public static void tokenClear() {
TOKEN_CACHE.clear();
}
}