前言
废话不多说,昨天是实现同源部署返回不同cookie,现在是核心,就是一个浏览器同时登录,客户端、运营端同时正常使用。
一、核心实现
核心实现实际上就是自定义HttpSessionIdResolver处理sessionid解析,上一篇博文已实现,地址:同源部署自定义sessionId解析器设置不同名称cookie
二、实现双登正常使用
其实就是自定义的HttpSessionIdResolver的MyHttpSessionIdResolver里的一个resolveSessionIds方法修改下,再前端传参配合下。
1.具体代码
代码如下(示例):
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.easylinkin.security.context.LinkappUserContextProducer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.session.web.http.CookieHttpSessionIdResolver;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.session.web.http.HttpSessionIdResolver;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
/**
* 自定义SessionId解析器
*
* @author zhengwen
*/
@Slf4j
//@Service("httpSessionIdResolver")
public class MyHttpSessionIdResolver implements HttpSessionIdResolver {
@Resource
private LinkappUserContextProducer linkappUserContextProducer;
/**
* CookieName默认名称
*/
public static final String CookieName = "LINKAPP_SESSION_ID";
/**
* sessionIdName
*/
private String sessionIdName = CookieName;
/**
* cookieHttpSessionIdResolver
*/
private CookieHttpSessionIdResolver cookieHttpSessionIdResolver;
/**
* 构造函数
*/
public MyHttpSessionIdResolver() {
initCookieHttpSessionIdResolver();
}
/**
* 构造函数
*
* @param sessionIdName sessionIdName
*/
public MyHttpSessionIdResolver(String sessionIdName) {
this.sessionIdName = sessionIdName;
initCookieHttpSessionIdResolver();
}
/**
* 初始化cookieHttpSessionIdResolver
*/
public void initCookieHttpSessionIdResolver() {
this.cookieHttpSessionIdResolver = new CookieHttpSessionIdResolver();
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setCookieName(this.sessionIdName);
this.cookieHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
}
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
String source = request.getHeader("source");
if (StringUtils.isNotBlank(source)) {
//这个里面的是核心,就是处理双登后,session会话请求接口时处理对应sessionId返回,让可以进行下一个方法setSessionId()
String reqSessionId = request.getHeader(source);
return (reqSessionId != null) ? Collections.singletonList(reqSessionId) : Collections.emptyList();
} else {
// cookie
List<String> cookies = cookieHttpSessionIdResolver.resolveSessionIds(request);
if (CollUtil.isNotEmpty(cookies)) {
return cookies;
}
// header
String headerValue = request.getHeader(this.sessionIdName);
if (StrUtil.isNotBlank(headerValue)) {
return Collections.singletonList(headerValue);
}
// request parameter
String sessionId = request.getParameter(this.sessionIdName);
return (sessionId != null) ? Collections.singletonList(sessionId) : Collections.emptyList();
}
}
@Override
public void setSessionId(HttpServletRequest request, HttpServletResponse response, String sessionId) {
log.info(CookieName + "={}", sessionId);
String source = request.getHeader("source");
if (StrUtil.isNotBlank(source)) {
this.sessionIdName = source;
initCookieHttpSessionIdResolver();
response.setHeader(source, sessionId);
} else {
response.setHeader(this.sessionIdName, sessionId);
}
this.cookieHttpSessionIdResolver.setSessionId(request, response, sessionId);
}
@Override
public void expireSession(HttpServletRequest request, HttpServletResponse response) {
response.setHeader(this.sessionIdName, "");
this.cookieHttpSessionIdResolver.setSessionId(request, response, "");
}
}
还需要的配合就是,登录接口从response的Header里取到sessionId,然后后面所有的接口请求都需要携带,例如:
source是前端固化的终端标识,我们另一个终端的标识就是admin。
下面的aep:198ced13-f21d-4ad5-b80b-edf09e983361就是从登录接口返回的response的header里获取的(同样是key代表返回的终端标识,值就是sessionId)
这个sessionId其实也没有什么好神秘的,也就是跟cookie值是base64加密解密关系。
后面其实可以增加sessionId、cookie、终端,3个维度校验,验证传参与终端一致。
总结
- cookie、session会话关系要清楚理解(理解不清这一切不可为)
- security安全机制还是很强悍的
好,就写到这里希望可以帮到大家,uping