考虑以下场景:
我有两个发布服务器来服务调度程序后面的请求,调度程序正在执行一些负载平衡机制,以循环方式在两个服务器之间分发请求。
用例:
用户从登录页面输入登录凭据,然后单击“提交”。调度程序将请求定向到“发布服务器 1”。身份验证成功后,将向客户端提供会话 ID,并将相应的会话信息存储在“Publish 1”上。
用户点击另一个受保护的页面,但调度程序将请求重定向到“发布服务器 2”,该服务器没有与会话 ID 对应的会话信息。
合理的结果: 会话被重置,并提示用户再次登录。
如何处理这样的需求?
注意: 我的用户不在 AEM 中,正在从数据库验证用户的真实性。
P.S.: 我已经去过一些博客,它们说 AEM 不支持 Http Session 集群,但没有一个提供正确的解决方案。
一种替代方法是使用网络路由。我们使用负载均衡器,它可以配置为启用粘性会话。它实质上添加了一个 cookie,用于后续请求将用户路由到用户第一次访问的同一发布者。这是一个非 AEM 解决方案,纯粹是网络和负载均衡器的一个功能,因此在您的情况下它可能是也可能不是一个选项。 AEM 调度程序配置还允许
stickyConnections
配置,这听起来像是在网络负载均衡器中完成相同的事情。
另见
您可以执行以下操作
在调度程序和负载均衡器(如果有的话)上启用粘性会话
#Allowing Sticky sessions
/stickyConnectionsFor "/content/brand/en-us"
启用会话管理
#Configuration to increase session timeout limit
/sessionmanagement
{
/directory "/mnt/var/www/html/content/.sessions"
/header "Cookie:login-token"
/timeout "3600"
}
PS: 3600s=60mins
两种可能的解决方案-
1)如果外部IDP提供了认证服务,则将认证信息存储在cookie中。无论发布者请求到哪个,它都会使用 cookie 中的信息,并将与 IDP 服务检查会话。
2) 如果使用您的自定义身份验证处理程序,则在调度程序中使用粘性会话,这将确保请求返回到会话处于活动状态的同一发布者。
这是个老问题,可以用Redis Cache之类的东西解决。 Redis是内存数据库中的键值对。它就像地图或一个非常大的 JSON 文档。 这种方法不需要粘性连接。
您可以将数据保存在 Redis 中,而不是将数据保存在 Session 中。 例如。 Key=JSESSIONID OR A CUSTOM COOKIE and value=YourObject(你当前保存在会话中) 所以关键是你的发布实例会将会话数据保存到 redis 中并从 redis 本身获取。
BinaryJedis jedis = RedisUtility.getJedisInstance();
Customer customer = new Customer();
customer.setFirstName(request.getParameter("firstName"));
customer.setLastName(request.getParameter("lastName"));
customer.setCustomerId(request.getParameter("customerId"));
String jSessionId = request.getCookie("JSESSIONID").getValue();
byte[] value = RedisUtility.serialize(customer);
jedis.set(jSessionId.getBytes(), value);
response.setContentType("application/json");
PrintWriter writer = response.getWriter();
writer.print("{'success':'true'}");
Redis 实用程序
public final class RedisUtility {
private static BinaryJedis bJedis;
public static synchronized BinaryJedis getJedisInstance() {
if (bJedis == null) {
bJedis = new BinaryJedis("localhost",6379);
}
return bJedis;
}
public static byte[] serialize(Serializable obj) {
return SerializationUtils.serialize(obj);
}
public static Object deserialize(byte[] bytes) throws ClassNotFoundException, IOException {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object object = ois.readObject();
return object;
}
}
从 Redis 中获取值
try {
BinaryJedis jedis = RedisUtility.getJedisInstance();
String jSessionId = req.getCookie("JSESSIONID").getValue();
logger.info("JSESSONID {}",jSessionId);
byte[] value =jedis.get(jSessionId.getBytes());
logger.info("Value from Redis {}",value);
if(value!=null) {
Customer cust = (Customer) RedisUtility.deserialize(value);
Gson gson = new Gson();
resp.getWriter().write(gson.toJson(cust));
return;
}
}