在使用FineReport报表系统中,处于账户安全考虑,有些企业希望同一账号在任意时刻智能在统一客户端登录。那么当A用户在C1客户端登陆后,该账号又在另外一个C2客户端登陆,服务器如何取判断呢?

开发原理

当服务器在得知A在C1登陆后,在cookie里面写入一个标识ID~将浏览器标记,然后以后的访问自然就能够根据匹配用户名和对应的标记来确定这个用户是不是在换浏览器登陆了,当匹配到用户异地登陆,就要把之前已经登陆的用户先登出,再登陆新请求的用户。当然关闭页面事件里要向后台先发送一个请求,后台要记得清除改用户标记的缓存。

那么客户端怎么知道自己的账号在异地登陆了呢?

这个就要基于心跳了~因为我们的http不是长连接的,所以只能模拟了,弄一个轮询ajax不断的问服务器,我是否在异地登陆,因为之前服务器任何一个账号登陆都会又一个ID标识,那么当接收到一个客户端心跳时,我们只要拿出里面的ID和用户名跟保存的匹配~匹配到存在该用户名,但是ID不对,那说明一定是另外一个客户端登陆了这个账号了,这个时候就告知客户端,你的账号已经异地登陆,然后前端提示刷新就可以了。

如何实现?

这里要用到FineReport提供的接口,RequestInterceptor

接口内容

package com.fr.stable.fun;import com.fr.stable.fun.mark.Layer;import com.fr.stable.fun.mark.Mutable;import com.fr.stable.web.RequestCMDReceiver;/*** Created by richie on 16/8/9.* 请求拦截器,通过传递op和cmd进行内置请求的拦截*/public interface RequestInterceptor extends Mutable, RequestCMDReceiver, Layer {String MARK_STRING = "RequestInterceptor";int CURRENT_LEVEL = 1;}

相关引用类

package com.fr.stable.web;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/*** Created by richie on 16/8/9.* 请求接收器*/public interface RequestCMDReceiver {/*** cmd参数值* @return cmd参数值*/String getCMD();/*** 执行* @param req http请求* @param res http应答* @param sessionID 会话ID* @throws Exception 处理失败则抛出异常*/void actionCMD(HttpServletRequest req, HttpServletResponse res,String sessionID) throws Exception;/*** 执行请求* @param req http请求* @param res http响应* @throws Exception 处理失败则抛出异常*/void actionCMD(HttpServletRequest req, HttpServletResponse res) throws Exception;}

注册方式

<extra-core><RequestInterceptor class="com.fr.plugin.xxx.youclassname" op="fs_load" cmd="login" pid="com.fr.plugin.xxx.name"/></extra-core>

其中pid的值应该和插件的id值一致,通过这样的注册方式,就可以使用自己定义的处理逻辑来覆盖掉默认的登录验证请求。

以上,通过故意制造报错的方式我们能够看到~FR登陆请求都是继承于

com.fr.fs.web.service.FSLoadLoginAction 这个类的~、

进一步反编译JAR可以看到~这个类是继承于

com.fr.web.core.ActionNoSessionCMD  最后实现 ActionCMD, RequestInterceptor

那么正好,我们的插件主类就可以免去很多自己写,直接继承于FSLoadLoginAction就可以用来处理所有的自定义登陆请求

【凡是需要在登陆时做得事情都可以在这里做】

当然actionCMD(HttpServletRequest req, HttpServletResponse res)这个执行方法还是要重写的~

还有就是protected void signOnSuccess(HttpServletRequest req, HttpServletResponse res, PrintWriter writer, String url)这个登陆成功之后需要做一些上面说的操作~

下面是两个代码片段,主要就是处理登陆标记和登出清除的.

片段1

@Overridepublic void actionCMD(HttpServletRequest req, HttpServletResponse res)throws Exception {String username = WebUtils.getHTTPRequestParameter(req, Constants.FR_USERNAME);String heartBeat = WebUtils.getHTTPRequestParameter(req, "__heartbeat__");if(ComparatorUtils.equals(heartBeat, "__active__")){if(StringUtils.isEmpty(username)){username = WebUtils.getHTTPRequestParameter(req, "__username__");if(!StringUtils.isEmpty(username)){req.getSession(true).removeAttribute("__username__");}}//如果用户名不为空且已登录的列表中不包含该用户名说明已经被踢下线if(!StringUtils.isEmpty(username) && !log.containsKey(username)){writeResult(res,false);return ;}//如果在已登录的列表中找到了该用户名的记录,但是ID不匹配也说明被踢下线了if(log.containsKey(username)){String crtUUID = WebUtils.getHTTPRequestParameter(req, "_sessionid_");SingleLoginBean logBean = log.get(username);String oldId = logBean.getId();if(!ComparatorUtils.equals(crtUUID,oldId)){writeResult(res,false);return;}else{//将当前时刻设置为最近活跃时刻logBean.setWait4removeTime(new Date().getTime());}}writeResult(res,true);//登出太久不活跃的用户 30S以上checkAllUser();return;}super.actionCMD(req, res);}

片段2

protected void signOnSuccess(HttpServletRequest req, HttpServletResponse res, PrintWriter writer, String url) throws IOException, JSONException {String username = WebUtils.getHTTPRequestParameter(req, Constants.FR_USERNAME);String uuid = req.getSession(true).getId();SingleLoginBean logBean = new SingleLoginBean(uuid,req,res,req.getSession(true));logBean.setWait4removeTime(new Date().getTime());//后面的用户登录成功后需要先将旧的用户转移到等待删除的列表中remove4logout(req);//将新登录的用户添加到已经登录的用户中log.put(username, logBean);if ("true".equals(WebUtils.getHTTPRequestParameter(req, ParameterConsts.__REDIRECT__))) {res.sendRedirect(url);} else {writer.print(JSONObject.create().put("url", url));}}gf =

下面就是JS轮询了

var askServer4Active = function(){var sessionid = getCrtSessionid();if( sessionid == "" || sessionid == null ){return ;}var url = FR.servletURL+"?op=fs_load&cmd=login&__heartbeat__=__active__&_sessionid_="+sessionid;FR.ajax({  url: url,  type: "POST",  dataType:"JSON",success: function(msg){  if(!msg.success){if(active){active = false;clearInterval(timer);FR.Msg.alert("警告","您的账号已在其他客户端登陆!\n如非本人授权,请及时修改密码!\n3秒后页面将跳转至登陆页!");setTimeout(function(){document.location = FR.servletURL+"?op=fs";},3000);}}else{active = true;}}  });};

  

转载于:https://www.cnblogs.com/laoA188/p/6202516.html

FineReport:任意时刻只允许在一个客户端登陆账号的插件相关推荐

  1. qt自定义按钮类,每个按钮自带一个右键弹出框,如何使同一时刻只显示一个弹出框

    提要 继承于QPushButton的自定义按钮类,其右键弹出一个弹框,创建多个这样的自定义按钮在窗口中,每一时刻只显示一个右键弹出框,避免同一时刻,多个按钮右键弹出弹出框后,未及时关闭弹出框导致的同一 ...

  2. android 之手机客户端登陆

    今天要学的例子是通过android 手机客户端登陆到服务器.验证是否登陆成功. 首先:我们在myEclipse 中新建一个web项目提供手机客户端的登陆请求,并做出响应,我们使用struts2.1.8 ...

  3. t6登录显示连接不到服务器,t6客户端登陆不到服务器

    t6客户端登陆不到服务器 内容精选 换一换 该操作只在跨AZ部署HA场景下才需要执行.EVS无法实现跨AZ磁盘共享,所以在跨AZ部署HA场景中,需要规划三台弹性云服务器,在每台云服务器上各绑定一块SC ...

  4. PHP实现同一个账号只能在一个终端登陆

    一个账号在a电脑登陆了,此时在b电脑登陆,就会将a踢下线,需要解决两个问题: 一.确保账号只能在一个地方登陆: 二.登陆后发送消息通知: 对于第一个问题,我们可以借助于session存储于redis之 ...

  5. 计算任意时刻椭圆轨道上行星的位置的插值方法

    目录 需求 搜集到的方法和问题 直接用牛顿力学公式进行模拟的问题 物理常数调整问题 初始化参量不直观 实时求解动力学微分方程 插值方法 问题简化 求解 θ ( t ) \theta(t) θ(t) ( ...

  6. linux pptp客户端_linux pptp客户端登陆pptp服务器

    Fedora14使用pptp客户端 虽然Fedora 自带的network manager已经带有了vpn的设置功能.但是使用起来非常不方便,经常出现无法连接的情况,初次设置的时候也很容易出错. 最近 ...

  7. [Android] 任意时刻从子线程切换到主线程的实现

    [Android] 任意时刻从子线程切换到主线程的实现 - Android移动开发技术文章_手机开发 - 红黑联盟 转载于:https://www.cnblogs.com/melons/p/57919 ...

  8. NSURLSessionDataTask与NSOperationQueue实现多文件断点下载(任意时刻终止进程,重启应用,自动重启下载)...

    效果展示 gif有点大,直接连接:7qnbrb.com1.z0.glb.clouddn.com/download.gi- 知识要点 NSOperationQueue线程队列的管理 NSURLSessi ...

  9. 使用客户端登陆ftp 500 OOPS: cannot change directory:/home/virftp解决

    使用客户端登陆ftp 500 OOPS: cannot change directory:/home/virftp解决 可以在windows上使用一ftp客户端来尝试进行登录.这个时候一般都会报一个错 ...

最新文章

  1. Opencv函数手册
  2. 香港的CIA线服务器是什么?
  3. [react] 使用PropTypes和Flow有什么区别?
  4. 面试题,客户经常变更需求该如何处理?
  5. es6 箭头函数使用_如何使用ES6箭头功能使JavaScript易于阅读
  6. 分布式光伏贷款欲破冰 多家银行推出相关业务
  7. F5 在 Gartner 魔力象限中被评为 Web 应用防火墙领导者
  8. 收集的图像处理网站http://blog.csdn.net/chief1985/article/details/1898358
  9. Talk预告 | 上海交通大学计算机系博士生李杰锋方浩树:多人场景,全身136关键点检测与跟踪框架AlphaPose技术讲解
  10. word 保存时 不能保存
  11. ubuntu安装I219-LM网卡驱动
  12. 我的面试题. 业务抽象能力测试.
  13. 如何使用预约旺进行免费的在线平台预约
  14. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.cy.pj.goods.dao
  15. (休息几天)读曼昆之微观经济学——供求关系
  16. 数据库作业3:第二章课后题(关系数据库及相关概念)
  17. guava之EventBus
  18. 如何跟领导说话,会让领导喜欢并器重你?
  19. android虹软人脸识别简书,Android 用虹软SDK做人脸识别
  20. chromium 源码目录结构

热门文章

  1. 预告 | 4月22日,CVPR 2021论文分享会详细介绍,学术新星云集!
  2. CVPR 2020 分方向论文大盘点合集
  3. 计算机视觉研究入门全指南
  4. 利用Python写俄罗斯方块游戏
  5. js添加关闭功能_微信小程序开发之添加夜间模式功能
  6. 谷歌开源EfficientNets:ImageNet准确率创纪录,效率提高10倍
  7. enum java 比较_Kotlin与Java比较:枚举类
  8. python展示全部好友_python爬所有好友头像
  9. ARM全新Armv9架构:10年最大更新、增强AI和security能力
  10. 梯度下降法快速教程 | 第二章:冲量(momentum)的原理与Python实现