Session &Cookie
来源:互联网 发布:卖衣服打折怎么计算法 编辑:程序博客网 时间:2024/06/05 16:59
Session &Cookie
概念:
由于Http是无状态的,即一次http请求,服务端给出响应后,即断开服务,下次请求需要重建链接,在这两次的交互中,服务器是不知道这两次的客户端信息是否相同,为了跟踪用户的会话,提出了session和cookie机制。
Cookie通过客户端来记录用户信息。
Session通过服务端来记录用户信息。
Cookie:实际上是一小段文本信息,每次客户端访问时都加上这段信息,这样服务器就能拿到request中的信息,进行解析,然后确认用户身份。
Session:客户端首次访问服务端时,服务端会生成用户的一些信息,用hashMap进行保存,同时会返回一个sessionId,以cookie的形式作为response返回给客户端,在之后的会话期间,客户端的请求加上sessionId即可,服务端拿到request之后,会根据sessionId,去hashMap中找有没有httpSession,有的话就拿出来使用。
具体介绍:
Cookie属性:
Name:cookie的名称
Value:cookie的值,一般需要加密
maxAge:失效时间,负数表示临时cookie,关闭浏览器即失效;0表示删除该cookie,正数表示在maxAge秒之后失效。
Secure:是否使用安全传输协议。如https,ssl等
Path:cookie的路径,必须要以“/”结束。如设置为“/root/”,则只有contextPath为"/root"的程序可以访问Cookie,如果设为"/",则代表本域下的contextPath都可访问该Cookie。
Domain:域,必须以"."开头,如".jd.com",则所有"jd.com"结尾的域名服务都可以访问该cookie。如果跨域,比如360buy.com的旧接口就无法解析从.jd.com过来的请求。需要服务端进行特殊处理
Comment:备注
Version:版本
如:
Cookie生命周期:
主要是根据expire/max_age来判断,过期则失效。我们现在是用持久化cookie来解决会话问题,服务端保存了cookie用户的上下文对象,里面有cookie的创建时间,超时时间等,会对cookie的过期时间有个控制,拦截器来控制,比如用户请求后,服务端拿到cookie后,判断超时时间,如果剩余1/3的时间,可以重新刷新超时时间。
public String intercept(ActionInvocation invocation) throws Exception {
//如果登录成功,则继续调用,否则返回
//判断是否配置了cookie的cookie名称
ActionContext actionContext = invocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE);
String value = cookieUtils.getCookieValue(request, loginCookieKey);
if (StringUtils.isNotBlank(value)) {//能取到值
LoginContext context = getLoginContext(value);
if (context != null) {//又能解出来
long current = System.currentTimeMillis();
long created = context.getCreated();
long expires = context.getExpires();
long timeout = expires == 0 ? sessionTimeout * 1000 : expires - created;//如果没有设置过期时间,则使用默认的
if (current - created < timeout) { //如果没有过期
LoginContext.setLoginContext(context);
if ((current - created) * rate > timeout) {//如果剩下的时间只有2/3,就需要重新派发cookie
log.error("session cookie[" + loginCookieKey + "] rewrite!");
//写最后一次访问的cookie
context.setCreated(current);
if (expires != 0) {
context.setTimeout(timeout);
}
cookieUtils.setCookie(response, loginCookieKey, context.toCookieValue());
}
//如果没过期,则继续调用
return invocation.invoke();
} else {
log.error("session cookie[" + loginCookieKey + "] is valid!");
//超时后,要清空 ,返回客户端
cookieUtils.invalidate(request, response);
}
} else {
log.error("session cookie[" + loginCookieKey + "] is error!");
}
}
Session生命周期:
为提高效率,服务器一般把session放入内存。每个用户都会有独立的session。如果session过于复杂,大量用户访问时就会内存溢出,所以,session应越小越好。Session是用户第一次访问服务器的时候创建的。用户关闭浏览器后session事实上并没有消失,还在内存中,一直等到过期才会消失。平时所说的消失,其实是指用户关闭浏览器重新打开后重新生成了新的session而已。Session生成后,只要用户继续访问,服务器就会更新session的最后访问时间,并维护该session。
Session属性:
setAttribute:map设值
getAttribute:获取value
getId():获取sessionid
Session共享:
1. 单独的session应用服务器
2. Session保存到缓存服务器中。
3. 基于NFS(Net File System),只需将共享目录服务器mount到各频道服务器的本地session目录即可。缺点是NFS依托于复杂的安全机制和文件系统,因此并发效率不高,尤其对于session这类高并发读写的小文件,会由于共享目录服务器io过高,拖垮web应用程序执行效率。
4. 基于数据库session共享。
5. 基于cookie的session共享: 将用户的session信息机密,序列化,统一放在根域名下。利用浏览器访问该根域名下的所有二级域名站点时,会传递与之域名对应的所有cookie内容的特性,从而事项用户的cookie化session在多服务间的共享。该方案不需要额外的服务器资源,但受到http协议头长度的限制,所以cookie在传递的时候要小,而且还要有有效的加密措施。这种策略优势比较明显,目前公司采用的就是这种方式。
Cookie模拟session的实例
1. 客户端获取RSA公钥
public String execute() {
try {
log.info("-----------存入公钥开始----------");
KeyPair keyPair = RSABuilder.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
this.privateKeyStr = Base64.encodeBytes(privateKey.getEncoded());
PublicKey publicKey = keyPair.getPublic();
this.publicKeyStr = Base64.encodeBytes(RSABuilder.confuse(publicKey.getEncoded()));
returnResult.setCode(ResultCode.SUCCESS.getCode());
returnResult.setMessage(this.publicKeyStr);//把公钥返回给客户端
StringBuilder key = new StringBuilder();
key.append(c.getUuid());
if(StringUtils.isNotBlank(c.getAsid())){
key.append(c.getAsid());
}
cacheUtils.set(key.toString(), 60 * 5, this.privateKeyStr);
log.info("uuid:" + c.getUuid() + "|publicKey:" + publicKeyStr + "|privateKey:" + privateKeyStr);
} catch (Exception e) {
log.error(e);
}
return SUCCESS;
}
2. 客户端获取DES私钥
RsaDecoder rsaDecoder = RsaDecoder.getInstance(privateKey);
String desKey = rsaDecoder.dencrypt(envelopeKey);//解密客户端传过来的随机数
log.info("uuid:" + c.getUuid() + "|dencryptContent:" + desKey);
HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE);
JdAppLoginContext context = JdAppLoginContext.getLoginContext();
if (context == null) {
context = new JdAppLoginContext();
}
String sessionKey = DESCoder.initKey();
log.info("uuid:" + c.getUuid() + "sessionKey:" + sessionKey);
context.setSessionKey(sessionKey);
JdAppLoginContext.setLoginContext(context);
loginCookieUtil.setTwoDomainCookie(request, response, loginCookieKey, context.toCookieValue());
returnResult.setCode(ResultCode.SUCCESS.getCode());
//服务端生成一个sessionkey,用客户端传过来的key把这个sessionkey加密,然后发给客户端,之后客户端用这个sessionkey进行正文加密,服务端再解开就行了
String message = DesUtil.encrypt(sessionKey, desKey);
returnResult.setMessage(message);
3. 加密登录信息进行登录,成功后写cookie
if (loginAndRegisterResult.isSuccess()) {
HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE);
JdAppLoginContext context = JdAppLoginContext.getLoginContext();
if (context == null) {
context = new JdAppLoginContext();
}
context.setPin(loginAndRegisterResult.getUserPin()); //设置pin
JdAppLoginContext.setLoginContext(context);
String cookieValue = context.toCookieValue();
//用新的包装方法设置cookie,保证如果是360buy请求的就设为360buy的domain,如果是jd请求的,就设为jd的domain
loginCookieUtil.setTwoDomainCookie(request,response, loginCookieKey, cookieValue);
//写cookie的同时写入响应体中
loginAndRegisterResult.setAppLogin(cookieValue);
//设置响应体,让wap网关不代理
response.setContentType("application/json;charset=utf-8;X-Wap-Proxy-Cookie=none");
//写入日志:
loginAnalysisService.insert(request, "音乐登录", loginAndRegisterResult.getUserPin());
}
4. 用户下次访问时,先进拦截器,拿到客户端cookie,解密,看能否解开,如果能解开说明已经登录,如果解不开说明没登陆。
String value = loginCookieUtil.getCookieValue(request, loginCookieKey);
log.error("**************************** 在HttpServletRequest中拿cookie-----"+"loginCookieKey等于"+loginCookieKey+" 结果"+value);
if (StringUtils.isNotBlank(value)) {//能取到值
LoginContext context = getLoginContext(value);
long current = System.currentTimeMillis();
long created = context.getCreated();
long expires = context.getExpires();
long timeout = expires == 0 ? sessionTimeout * 1000 : expires - created;//如果没有设置过期时间,则使用默认的
if (current - created < timeout) { //如果没有过期
LoginContext.setLoginContext(context);
if ((current - created) * rate > timeout) {//如果剩下的时间只有2/3,就需要重新派发cookie
log.error("session cookie[" + loginCookieKey + "] rewrite!");
//写最后一次访问的cookie
context.setCreated(current);
if (expires != 0) {
context.setTimeout(timeout);
}
loginCookieUtil.setCookie(response, loginCookieKey, context.toCookieValue());
}
//如果没过期,则继续调用
return invocation.invoke();
} else {
log.error("session cookie[" + loginCookieKey + "] is valid!");
//超时后,要清空 ,返回客户端
loginCookieUtil.invalidate(request, response);
}
}
跟踪客户状态的方法:
1. 建立含有跟踪数据的隐藏字段,即hidden域
2. 重写包含额外参数的URL
3. 使用持续的Cookie
4. 使用Session
区别:
1. Cookie是保存在客户端的,session是保存在服务端的。
2. Cookie不是很安全,可以分析本地的cookie进行cookie欺骗。
3. Session保存在服务器上,如果过期时间较长,会占用服务器资源。考虑减轻服务器性能,可以考虑Cookie。
4. 用Session的话,需要考虑session共享问题,如分布式缓存,单独的session服务器等。
- Session,Cookie
- cookie & session
- Cookie & Session
- Session, Cookie
- Session、Cookie
- SESSION && COOKIE
- Cookie & Session
- SESSION && COOKIE
- Session.Cookie
- cookie session
- session cookie
- session cookie
- Cookie&Session
- cookie session
- Cookie&Session
- Cookie、Session
- cookie&session
- Cookie & Session
- 在cocos2d里添加UITextField
- addActionListener
- POJ 1012 Timing Limit Exceed问题
- 收到了TexturePack的使用许可
- Sqlyog字段的各属性的意思
- Session &Cookie
- 品味细节之java方法重载调用细节
- 递归案例
- C++11智能指针
- C# WPF 项目中无法使用Console输出时出现句柄无效的IO异常解决方法
- NYOJ a problem is easy
- Android实现左右滑动指引效果
- JQuery中阻止事件冒泡方式及其区别
- 将引用做为传递参数