com.alogic.auth.SessionManager Maven / Gradle / Ivy
package com.alogic.auth;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.Script;
import com.alogic.xscript.doc.XsObject;
import com.alogic.xscript.doc.json.JsonObject;
import com.anysoft.util.*;
import com.anysoft.webloader.HttpClientTool;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import com.logicbus.backend.Context;
import com.logicbus.backend.server.http.HttpContext;
import java.util.HashMap;
/**
* 会话管理器
*
* @author duanyy
* @since 1.6.10.10
*
* @version 1.6.11.7 [20180107 duanyy]
* - 优化Session管理
*
* @version 1.6.11.27 [20180417 duanyy]
* - 修正SessionManager获取cookies的空指针问题
*
* @version 1.6.11.30 [20180514 duanyy]
* - 增加全局xscript脚本函数库
*
* @version 1.6.12.11 [20181206 duanyy]
* - 浏览器cookie可定制httpOnly和secure属性
*
* @version 1.6.12.18 [20190104 duanyy]
* - 增加会话保持功能
*
* @version 1.6.14.12 [20210617 duanyy]
* - cookie可支持SameSite属性
*
*/
public interface SessionManager extends Configurable,XMLConfigurable,Constants{
/**
* 从Context中获取Session
*
*
* 用来从服务调用Context中获取当前的Session实例,当当前Session不存在的时候,如果create为true,则创建Session,反之返回为null.
*
* @param ctx 服务调用上下文
* @param create 是否创建
* @return 当前的Session实例
*/
public Session getSession(Context ctx,boolean create);
/**
* 从Request中获取Session
*
*
* 用来从HttpServletRequest中获取当前的Session实例,当当前Session不存在的时候,如果create为true,则创建Session,反之返回为null.
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param create 是否创建
* @return 当前的Session实例
*/
public Session getSession(HttpServletRequest request,HttpServletResponse response,boolean create);
/**
* 根据Id来获取Session对象
* @param sessionId id
* @param create 是否创建
* @return Session对象
*/
public Session getSession(String sessionId,boolean create);
/**
* 根据id来删除Session对象
* @param sessionId id
*/
public void delSession(String sessionId);
/**
* 获取指定的Cookies值
* @param req HttpRequest
* @param name Cookies名称
* @param dft 缺省值
* @return Cookies值
*/
public String getCookie(HttpServletRequest req,String name,String dft);
/**
* 设置cookie
* @param response httpResponse
* @param name cookie名称
* @param value cookie值
* @param path 路径
* @param ttl ttl
*
*/
public void setCookie(HttpServletResponse response,String name,String value,String path,int ttl);
/**
* 创建一个新的cookie
* @param name cookie名称
* @param value cookie取值
* @param path cookie的路径
* @return Cookie实例
*/
public Cookie newCookie(String name,String value,String path);
/**
* 设置一个已经创建好的cookie
* @param response httpResponse
* @param cookie cookie实例
*/
public void setCookie(HttpServletResponse response,Cookie cookie);
/**
* 虚基类
* @author duanyy
*
*/
public abstract static class Abstract implements SessionManager{
/**
* a logger of slf4j
*/
protected static final Logger LOG = LoggerFactory.getLogger(SessionManager.class);
/**
* 会话的生存期
*/
protected int ttl = 30 * 60;
/**
* 是否使用cookie来保存会话id
*/
protected boolean cookieEnable = false;
/**
* cookie的名称
*/
protected String cookieName = "tgc";
/**
* 会话保持的cookie
*/
protected String keepAliveCookieName = "false";
protected String cookieDomain = "";
protected boolean httpOnly = false;
protected boolean secure = false;
protected CookieManager.SameSite sameSite = CookieManager.SameSite.NULL;
protected String encoding = "utf-8";
/**
* 当缺省时执行脚本
*/
protected Logiclet onKeepAlive = null;
protected HttpClientTool httpClientTool = null;
@Override
public void configure(Properties p) {
ttl = PropertiesConstants.getInt(p,"ttl", ttl);
cookieEnable = PropertiesConstants.getBoolean(p,"cookieEnable", cookieEnable);
cookieName = PropertiesConstants.getString(p,"cookieName",cookieName);
cookieDomain = PropertiesConstants.getString(p,"cookieDomain",cookieDomain);
httpOnly = PropertiesConstants.getBoolean(p,"cookieHttpOnly", httpOnly);
secure = PropertiesConstants.getBoolean(p,"cookieSecure", secure);
keepAliveCookieName = PropertiesConstants.getString(p,"cookieKeepAlive",keepAliveCookieName);
encoding = PropertiesConstants.getString(p,"http.encoding",encoding);
sameSite = getSameSite(PropertiesConstants.getString(p,"cookieSameSite",sameSite.getAttributeValue()));
httpClientTool = Settings.getToolkit(HttpClientTool.class);
}
protected static CookieManager.SameSite getSameSite(String value){
if (value.equalsIgnoreCase(CookieManager.SameSite.LAX.getAttributeValue())){
return CookieManager.SameSite.LAX;
}
if (value.equalsIgnoreCase(CookieManager.SameSite.STRICT.getAttributeValue())){
return CookieManager.SameSite.STRICT;
}
if (value.equalsIgnoreCase(CookieManager.SameSite.NONE.getAttributeValue())){
return CookieManager.SameSite.NONE;
}
return CookieManager.SameSite.NULL;
}
@Override
public void configure(Element e, Properties p) {
XmlElementProperties props = new XmlElementProperties(e,p);
configure(props);
Element elem = XmlTools.getFirstElementByPath(e, "on-keep-alive");
if (elem != null){
onKeepAlive = Script.create(elem, props);
}
}
/**
* 获取当前的SessionId
* @param request HttpServletRequest
* @param create 是否创建
* @return 当前的SessionId
*/
protected String getSessionId(HttpServletRequest request,HttpServletResponse response,boolean create){
String sessionId = null;
//先从HttpSession中获取
if (cookieEnable){
sessionId = getCookie(request,cookieName,sessionId);
if (StringUtils.isEmpty(sessionId) && create){
sessionId = KeyGen.uuid();
setCookie(response,cookieName,sessionId,"/",ttl);
}
}else{
HttpSession httpSession = request.getSession(create);
sessionId = httpSession == null ? null : httpSession.getId();
}
return sessionId;
}
@Override
public Session getSession(Context ctx, boolean create) {
if (!(ctx instanceof HttpContext)){
throw new BaseException("core.e1002","The Context is not a HttpContext instance.");
}
HttpContext httpContext = (HttpContext)ctx;
HttpServletRequest request = httpContext.getRequest();
HttpServletResponse response = httpContext.getResponse();
return getSession(request,response,create);
}
@Override
public Session getSession(HttpServletRequest request,HttpServletResponse response,boolean create) {
if (StringUtils.isNotEmpty(keepAliveCookieName) && !BooleanUtils.toBoolean(keepAliveCookieName)){
String sessionId = getSessionId(request, response, true);
Session session = getSession(sessionId,false);
if (session != null){
return session;
}else{
session = getSession(sessionId,true);
if (session != null) {
String keepAliveCookie = this.getCookie(request, keepAliveCookieName, "");
if (StringUtils.isNotEmpty(keepAliveCookie)) {
//发现了会话保持cookie
if (onKeepAlive != null) {
Context ctx = new HttpContext(request, response, encoding);
LogicletContext logicletContext = new Context.ServantLogicletContext(ctx);
CookieManager cm = new CookieManager.Default(this, request, response);
try {
logicletContext.setObject(ID_SESSION, session);
logicletContext.setObject(ID_COOKIES, cm);
logicletContext.SetValue("$keepalive", keepAliveCookie);
logicletContext.SetValue("$service", "/auth/KeepAlive");
logicletContext.SetValue("$clientIp", httpClientTool.getClientIp(request));
XsObject doc = new JsonObject("root", new HashMap());
onKeepAlive.execute(doc, doc, logicletContext, null);
} finally {
logicletContext.removeObject(ID_SESSION);
logicletContext.removeObject(ID_COOKIES);
}
}
}
}
return session;
}
}else {
String sessionId = getSessionId(request, response, create);
return StringUtils.isNotEmpty(sessionId) ? getSession(sessionId, create) : null;
}
}
@Override
public String getCookie(HttpServletRequest req,String name,String dft){
Cookie [] cookies = req.getCookies();
if (cookies != null){
for (Cookie cookie:cookies){
if (cookie.getName().equals(name)){
return cookie.getValue();
}
}
}
return dft;
}
@Override
public void setCookie(HttpServletResponse response,String name,String value,String path,int ttl){
Cookie cookie = new Cookie(name,value);
cookie.setPath(path);
cookie.setMaxAge(ttl);
cookie.setSecure(secure);
cookie.setHttpOnly(httpOnly);
if (secure && sameSite != CookieManager.SameSite.NULL) {
cookie.setComment(sameSite.getCommentValue());
}
if (StringUtils.isNotEmpty(cookieDomain)){
cookie.setDomain(cookieDomain);
}
response.addCookie(cookie);
}
@Override
public Cookie newCookie(String name,String value,String path){
Cookie cookie = new Cookie(name,value);
cookie.setPath(path);
cookie.setMaxAge(ttl);
cookie.setSecure(secure);
cookie.setHttpOnly(httpOnly);
if (secure && sameSite != CookieManager.SameSite.NULL) {
cookie.setComment(sameSite.getCommentValue());
}
if (StringUtils.isNotEmpty(cookieDomain)){
cookie.setDomain(cookieDomain);
}
return cookie;
}
@Override
public void setCookie(HttpServletResponse response,Cookie cookie){
response.addCookie(cookie);
}
}
public static class SessionCleaner implements HttpSessionListener{
/**
* a logger of slf4j
*/
protected static final Logger LOG = LoggerFactory.getLogger(SessionManager.class);
@Override
public void sessionCreated(HttpSessionEvent se) {
LOG.info(String.format("Session %s is created", se.getSession().getId()));
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession sess = se.getSession();
if (sess != null){
LOG.info(String.format("Session %s has been destroyed.", sess.getId()));
SessionManager sm = SessionManagerFactory.getDefault();
sm.delSession(sess.getId());
}
}
}
}