WEB端

问题描述

WMS系统对监管仓进行访问(监管仓内嵌于WMS系统),但是需要登录监管仓系统才能看到引入WMS系统的界面,否则看不了监管仓。这里涉及到一个监管仓访问超时的问题:如果用户一直在WMS上操作,而对监管仓不闻不问,那么一般在30minutes 之后,再次点击监管仓页面就会发现打不开了;同理,如果用户一直停在监管仓操作,那么30minutes之后,回来再次访问WMS的页面的时候,WMS也会自动退出到登录界面。以上问题说明,两个系统使用的不是同一个session时,在同一个系统中操作时间越长,另一个系统session存活的几率就越小,不被用户操作的系统也最容易导致session死亡,大多数时候只能半开半闭式地访问,而不能灵活地游弋于多个系统。要解决session共享的问题才能实现多系统紧密协作。

处理方案

可以将session用一个公用的数据存储区块存储起来,如:memcache。利用memcache的数据超时来处理session。同时还可以实现单点登录,如果用户通过验证,但是memcache已经存在此session那么就不再允许用户登录系统。

移动端

问题描述

历史惊人的相似,在Android和IOS上分别访问WMS和监管仓的时候发现不能共享Token。因为此Token是WMS和监管仓都分别作了生成的,登录时也仅仅是对是否超时作了验证,所以在登录的过程中他们是没有问题的,但是访问其他系统页面后切换回来就是在用其他类系统的Token在访问自己的站点,所以导致Token通不过验证。我们并没有通知对方系统自己的Token已经变了,而是自以为是独立地工作。

处理方案

方法一:同上;

方法二:每个系统都提供交换Token的接口,改变了就通知对方系统,这样可以确保用户获取到的token永远都是最新的。

我觉得今天这个标题很有意思,值得大家深入去思考,上面的解决方案是余之鄙见,希冀更多处理方案!

Token实现代码

TOken实体
package com.wlyd.wms.service.api.data;import java.io.Serializable;public class UserToken implements Serializable
{private static final long serialVersionUID = -8766321739625153631L;private String signature;// 签名private String timestamp;// 时间戳private String random;// 随机数private String authorizationCode;//授权码public String getSignature(){return signature;}public void setSignature(String signature){this.signature = signature;}public String getTimestamp(){return timestamp;}public void setTimestamp(String timestamp){this.timestamp = timestamp;}public String getRandom(){return random;}public void setRandom(String random){this.random = random;}public String getAuthorizationCode(){return authorizationCode;}public void setAuthorizationCode(String authorizationCode){this.authorizationCode = authorizationCode;}@Overridepublic String toString(){return "signature=" + signature + "×tamp=" + timestamp + "&random=" + random+ "&authorizationCode=" + authorizationCode;}
}
C#与Java DES加密工具
package com.wlyd.wms.util.api;import java.security.Key;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import com.wlyd.wms.service.api.data.UserToken;
import com.wlyd.wms.util.Log;
import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;public class JCSharpDESUtil
{// DES加密的私钥,必须是8位长的字符串private static final byte[] DESkey = "11111111".getBytes();// 设置密钥private static final byte[] DESIV = "12345678".getBytes();// 设置向量static AlgorithmParameterSpec iv = null;// 加密算法的参数接口,IvParameterSpec是它的一个实现private static Key key = null;static{DESKeySpec keySpec;try{keySpec = new DESKeySpec(DESkey);// 设置密钥参数iv = new IvParameterSpec(DESIV);// 设置向量SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 获得密钥工厂key = keyFactory.generateSecret(keySpec);// 得到密钥对象} catch (Exception e){Log.getLogger(JCSharpDESUtil.class).error("");}}public static String encrypt(String data){try{Cipher enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");// 得到加密对象CipherenCipher.init(Cipher.ENCRYPT_MODE, key, iv);// 设置工作模式为加密模式,给出密钥和向量byte[] pasByte = enCipher.doFinal(data.getBytes("utf-8"));BASE64Encoder base64Encoder = new BASE64Encoder();return base64Encoder.encode(pasByte).replace("\n", "").replace("\r", "");// 去掉换行回车符} catch (Exception e){Log.getLogger(JCSharpDESUtil.class).error("加密异常:" + e.getMessage());}return "";}public static String decrypt(String data){try{Cipher deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");deCipher.init(Cipher.DECRYPT_MODE, key, iv);BASE64Decoder base64Decoder = new BASE64Decoder();byte[] pasByte = deCipher.doFinal(base64Decoder.decodeBuffer(data));return new String(pasByte, "UTF-8");} catch (Exception e){Log.getLogger(JCSharpDESUtil.class).error("解密异常:" + e.getMessage());}return "";}public static void main(String[] args) throws Exception{String data = "/YG1K/6/mh86b5EbjYdZwrNm+MGzGw7DXXzj1mBM3ssuw2BS2Xan9Yk1mBijRLoujGtD9Wo692KvVUoIvZZY9NdpJvgv76Rn";System.out.println("加密:" + JCSharpDESUtil.encrypt("boonya"));System.out.println("解密:" + JCSharpDESUtil.decrypt(JCSharpDESUtil.encrypt("boonya")));System.out.println("CShap data Length " + (data.getBytes().length % 8));System.out.println("CShap解密:" + JCSharpDESUtil.decrypt(data));UserToken encryptedToken = new UserToken();encryptedToken.setSignature("wmsadmin");encryptedToken.setTimestamp(Calendar.getInstance().getTimeInMillis() + "");encryptedToken.setRandom(new Random().nextInt(999999999) + "");String text = encryptedToken.toString();System.out.println("明文:" + text);String encryptData = JCSharpDESUtil.encrypt(text);System.out.println("加密:" + encryptData);System.out.println("解密:" + JCSharpDESUtil.decrypt(JCSharpDESUtil.encrypt(text)));long time = new Date().getTime();System.out.println(Calendar.getInstance().getTimeInMillis());System.out.println(new Date(Calendar.getInstance().getTimeInMillis()));System.out.println(time);}}
TOKEN工具类
package com.wlyd.wms.util;import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;import com.wlyd.wms.service.api.data.UserToken;
import com.wlyd.wms.util.api.JCSharpDESUtil;public class TokenUtil
{private static ConcurrentHashMap<String, UserToken> map = new ConcurrentHashMap<String, UserToken>();/*** 生成加密Token* * @param username* @return*/public static UserToken generateToken(String username){UserToken userToken = new UserToken();// 设置签名userToken.setSignature(username);// 设置时间戳userToken.setTimestamp(getTimeStamp());// 设置随机数userToken.setRandom(getRandom());// 设置授权码userToken.setAuthorizationCode(getAuthorizationCode(username));return userToken;}/*** 判定是否已经登录* * @param signature* @return*/public static boolean whetherUserHasSignedIn(String signature){if(map.containsKey(signature)){return true;}return false;}/*** 创建用户Token* * @param username* @return*/public static String createToken(String username){UserToken userToken = generateToken(username);// 保存用户TokenString token=encryptUserToken(userToken);map.put(encryptSignature(userToken.getSignature()), userToken);return token;}/*** 设置自定义的Token* * @param username* @param userToken*/public static void setSelfToken(String username,UserToken userToken){map.put(username, userToken);}/*** 【重新生成】更新Token* * @param token* @return*/public static String reCreateToken(String token){UserToken userToken=TokenUtil.analyseEncryptedUserToken(token);return createToken(userToken.getSignature());}/*** 加密签名* * @param username* @return*/public static String encryptSignature(String username){return JCSharpDESUtil.encrypt(username);}/*** 解密签名* * @param signature* @return*/public static String decryptSignature(String signature){return JCSharpDESUtil.decrypt(signature);}/*** 生成时间戳* @return*/public static String getTimeStamp(){return Calendar.getInstance().getTimeInMillis() + "";}/*** 生成随机数* * @return*/public static String getRandom(){return new Random().nextInt(999999999) + "";}/*** 加密用户Token* * @param userToken* @return*/public static String encryptUserToken(UserToken userToken){return JCSharpDESUtil.encrypt(userToken.toString());}/*** 解析加密用户Token* * @param token* @return*/public static UserToken decryptUserToken(String token){String decryptToken=JCSharpDESUtil.decrypt(token);String[] params = decryptToken.split("&");// 分析用户提交过来的TokenUserToken userToken = new UserToken();for (int i = 0, j = params.length; i < j; i++){String[] currentParams = params[i].split("=");String param = currentParams[0];switch (param){case "signature":userToken.setSignature(currentParams[1]);break;case "timestamp":userToken.setTimestamp(currentParams[1]);break;case "random":userToken.setRandom(currentParams[1]);break;case "authorizationCode":userToken.setAuthorizationCode(currentParams[1]);break;default:break;}}return userToken;}/*** 【解密用户Token】分析用户Token* * @param token* @return*/public static UserToken analyseEncryptedUserToken(String token){UserToken userToken=decryptUserToken( token);return userToken;}/*** 验证用户Token* * @param token* @param userToken* @return*/public static boolean verifyUserToken(String token){// 分析用户需要验证的TokenUserToken userToken=decryptUserToken(token);// 给用户加密签名String encryptSignature=encryptSignature(userToken.getSignature());// 判定是否包含此Tokenif(!map.containsKey(encryptSignature)){return false;}// 获取登录的用户TokenUserToken userTokenIner=(UserToken) map.get(encryptSignature);// 验证是否存在此用户登录的Tokenif (userTokenIner!=null&&(userToken.toString()).equals(userTokenIner.toString())){// 判定时间戳是否过期long currentTime = Calendar.getInstance().getTimeInMillis();long timestamp = Long.valueOf(userToken.getTimestamp());// Token有效时间为30分钟long verifyTime = 30 * 60 * 1000;if (currentTime - timestamp > verifyTime){// 移除过期的Tokenmap.remove(encryptSignature);return false;}return true;}return false;}/*** 获取已经签入的用户Token* * @return*/public static UserToken getUserSignedToken(String signature){if(map.containsKey(signature)){return map.get(signature);}return null;}/*** 根据用户名获取MD5Token* * @param username* @return*/public static String getAuthorizationCode(String username){SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");String date = sdf.format(new Date());String token = Md5.getPassSalt("username=" + username + "&date=" + date, Md5.getMD5Str(username));return token;}public static void main(String[] args) { String token=TokenUtil.createToken("boonya");System.out.println("token:"+token);System.out.println("Original token:"+TokenUtil.analyseEncryptedUserToken(token));boolean result=TokenUtil.verifyUserToken(token);System.out.println("verify reulst:"+result);}/*** 创建用户Token* * @param username* @return*/public static String createTokenIOS(String username){UserToken userToken = generateToken(username);map.put(encryptSignature(userToken.getSignature()), userToken);return userToken.toString();}public static UserToken decryptUserTokenIOS(String token){String[] params = token.split("&");// 分析用户提交过来的TokenUserToken userToken = new UserToken();for (int i = 0, j = params.length; i < j; i++){String[] currentParams = params[i].split("=");String param = currentParams[0];switch (param){case "signature":userToken.setSignature(currentParams[1]);break;case "timestamp":userToken.setTimestamp(currentParams[1]);break;case "random":userToken.setRandom(currentParams[1]);break;case "authorizationCode":userToken.setAuthorizationCode(currentParams[1]);break;default:break;}}return userToken;}/*** 解析token信息非加密* @MethodName: verifyUserTokenIOS * @Description: * @param token* @return* @throws*/public static boolean verifyUserTokenIOS(String token){// 分析用户需要验证的TokenUserToken userToken=decryptUserTokenIOS(token);// 给用户加密签名String encryptSignature=encryptSignature(userToken.getSignature());// 判定是否包含此Tokenif(!map.containsKey(encryptSignature)){return false;}// 获取登录的用户TokenUserToken userTokenIner=(UserToken) map.get(encryptSignature);// 验证是否存在此用户登录的Tokenif (userTokenIner!=null&&(userToken.toString()).equals(userTokenIner.toString())){// 判定时间戳是否过期long currentTime = Calendar.getInstance().getTimeInMillis();long timestamp = Long.valueOf(userToken.getTimestamp());// Token有效时间为30分钟long verifyTime = 30 * 60 * 1000;if (currentTime - timestamp > verifyTime){// 移除过期的Tokenmap.remove(encryptSignature);return false;}return true;}return false;}}
交换公钥工具类
package com.wlyd.wms.util.api;import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;import com.wlyd.wms.service.api.data.UserToken;public class UserSecurityManager
{private static ConcurrentHashMap<String, UserToken> TOKEN = new ConcurrentHashMap<String, UserToken>();/*** <k,v>:<sessionId,clientPublicKey>*/private static ConcurrentHashMap<String, String> CLIENT_PUBLIC = new ConcurrentHashMap<String, String>();/*** <k,v>:<sessionId,serverPublicKey>*/private static ConcurrentHashMap<String, String> SERVER_PUBLIC = new ConcurrentHashMap<String, String>();/*** <k,v>:<serverPublicKey,serverPrivateKey>*/private static ConcurrentHashMap<String, String> SERVER_PUBLIC_PRIVATE = new ConcurrentHashMap<String, String>();public static String getSessionId(String clientPublicKey){if(CLIENT_PUBLIC.containsValue(clientPublicKey)){for (Entry<String, String > entry: CLIENT_PUBLIC.entrySet()){if(entry.getValue().equals(clientPublicKey)){return entry.getKey();}}}return null;}public static ConcurrentHashMap<String, UserToken> getTOKEN(){return TOKEN;}public static void rememberUserToken(String key,UserToken token){TOKEN.put(key, token);}public static void removeUserToken(String key){if(TOKEN.containsKey(key)){TOKEN.remove(key);}}public static void rememberClientPublicKey(String sessionId,String clientPublicKey){CLIENT_PUBLIC.put(sessionId, clientPublicKey);}public static String getClientPublicKey(String sessionId){if(CLIENT_PUBLIC.containsKey(sessionId)){return CLIENT_PUBLIC.get(sessionId);}return null;}public static void removeClientPublicKey(String sessionId){if(CLIENT_PUBLIC.containsKey(sessionId)){CLIENT_PUBLIC.remove(sessionId);}}public static void rememberServerPublicKey(String sessionId,String serverPublicKey){SERVER_PUBLIC.put(sessionId, serverPublicKey);}public static String getServerPublicKey(String sessionId){if(SERVER_PUBLIC.containsKey(sessionId)){return SERVER_PUBLIC.get(sessionId);}return null;}public static String getServerPrivateKey(String sessionId){if(SERVER_PUBLIC.containsKey(sessionId)){String serverPublicKey= SERVER_PUBLIC.get(sessionId);if(SERVER_PUBLIC_PRIVATE.containsKey(serverPublicKey)){SERVER_PUBLIC_PRIVATE.get(serverPublicKey);}}return null;}public static void removeServerPublicKey(String sessionId){if(SERVER_PUBLIC.containsKey(sessionId)){SERVER_PUBLIC.remove(sessionId);}}public static void rememberServerPublicAndPrivateKey(String serverPublicKey,String serverPrivateKey){SERVER_PUBLIC_PRIVATE.put(serverPublicKey, serverPrivateKey);}public static void removeServerPublicAndPrivateKey(String serverPublicKey){if(serverPublicKey==null||serverPublicKey.equals("")) return;if(SERVER_PUBLIC_PRIVATE.containsKey(serverPublicKey)){SERVER_PUBLIC_PRIVATE.remove(serverPublicKey);}}}

跨系统如何保持Session存活和Token共享问题相关推荐

  1. 新蜂商城(newbee-mall-api)部分接口实验,跨域处理(同源策略,跨域访问,CORS),系统安全问题(Session,Cookie,Token,OAuth)(软件工程综合实践课程第十三周)

    文章目录 一.要求 二.知识总结 跨域处理 1.同源策略 1.1 浏览器的同源策略 1.2 跨域请求实验 2 跨域访问 2.1 添加响应头来处理跨域 2.1.1 CORS 跨域资源共享 2.1.2 设 ...

  2. 时间同步失败_跨系统历史数据同步脚本实战

    平时开发过程中可能会碰到令人头疼的历史数据同步问题,尤其是跨系统数据同步更加让人头疼.通常碰到这样的问题大家站稳.不要慌,可能只需写一个简单的同步脚本就可以解决. 实战场景 前段时间小北写过一个文章介 ...

  3. 用P3P header解决IE下iframe跨域访问时候session丢失的问题

    用P3P header解决IE下iframe跨域访问时候session丢失的问题 整合客户的登录时,或者其他一个网站通过iframe时,特别是一个http页面,访问一个https页面时,常常会sess ...

  4. ios android 录音格式,跨系统的录音格式兼容性问题: iOS Android

    iOS/ OS X支持的可播放的Audio Format与Android支持的有些不一样.因此可能出现在Android设备上面使用MediaRecorder录制出来的音频文件在iOS上面不可用.当然也 ...

  5. 跨系统远程登录用Linux系统远程登录windows7

    打开windows7---->开始菜单--->运行--->输入cmd--->输入ipconfig 查看网卡信息 如下图所示 打开Linux系统--->鼠标右击打开终端-- ...

  6. ASP.NET WebApi 基于分布式Session方式实现Token签名认证

    一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...

  7. 阴阳师哪些服务器可以跨系统转移,阴阳师怎么跨系统转服?跨系统转服方法介绍...

    阴阳师最近开启了跨系统角色转移服务试运行,为了满足大人们更换手机仍能继续游玩原角色的需求,寮办推出角色转移服务,转移后,仍使用原帐号进行登录,被转移角色所有内容均不变,只是登录平台发生改变,转移需要手 ...

  8. android系统里面的mic是哪个app_苹果记事app哪个好用?这款便签可以跨系统使用...

    张东生是一名毕业没多久的小伙子,进入了一家贸易公司之后,经过自己的努力,短短的时间内就成为了管理层之一.之所以有这么显著的成就,和他平时的工作习惯有很大关系,善用记事app就是他的一个"法宝 ...

  9. 使用 做签名的post_ASP.NET WebApi 基于分布式Session方式实现Token签名认证

    一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebServ ...

  10. 微软Build 2018展示Visual Studio功能:跨系统云编程

    5 月 8 日凌晨消息,微软 Build 2018 开发者大会在今天正式来开帷幕.很明显整场发布会被分为了上下两个部分,上半场如果说是聊一些技术实现和愿景,那下半场就应该说是实战说明了. 跨平台云端编 ...

最新文章

  1. 欧拉定理 费马小定理
  2. 7 款从 HTML 文档提取文本的工具
  3. 【附段错误原因,最后两个测试点】1052 Linked List Sorting (25 分)【链表类题目总结】
  4. HTTP缓存详解之etag
  5. 【官方搭建入门】JEEWX 捷微开发环境搭建必读
  6. @Service @Autowired
  7. bzoj1975 [Sdoi2010]魔法猪学院 a*+堆
  8. 实例浅析javascript call by value与call by reference
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的教学管理平台
  10. 1046. 划拳(15)-PAT乙级真题
  11. oracle数据库表空间追加数据库文件方法
  12. KMP算法的正确性证明及一个小优化
  13. Codeforces 145E Lucky Queries 线段树
  14. 饭卡可以用水冲洗吗_关于饭卡使用与管理的规定
  15. 英文打字测试C语言课程设计,语言设计打字练习题库.doc
  16. 手机投屏到电脑完美教程,安卓和苹果用户均可使用
  17. 以太网交换机如何工作以及MAC和PHY
  18. 10 款富有创意的博客名片设计
  19. mahout第一篇-----Mahout学习路线图
  20. 飞机大战-子弹的实现

热门文章

  1. 一文解决scrapy带案例爬取当当图书
  2. 排列组合公式/排列组合计算公式
  3. iphone快捷指令蚂蚁森林能量_iPhone“快捷指令”怎么玩?玩法太多,别让这个功能吃灰...
  4. 绩效管理系统(Performance Management System)
  5. 街区最短路径问题——曼哈顿距离
  6. 设计网站如何提高版式的设计水平?
  7. 零基础云开发一个投票小程序
  8. Iframe中,弹出层屏幕垂直居中
  9. [极客时间] 时间复杂度和空间复杂度分析
  10. bulma css 中文,Bulma CSS – 开始