SpringMVC拦截器实现单点登录

单点登录的功能在实际的应用场景中还是很重要的,逻辑上我们也不允许一个用户同时在进行着两个操作,下面就来了解一下SpringMVC的单点登录实现

SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理。

1,先探究一个基本的实现原理:这个功能还是比较简单的,就是对于同一个web项目同一个时间只能有一个用户在进行操作,所以这里就涉及到一个异地登录的发现,而这里就推出两条路,1是服务器发现已登录的用户通过另一个IP再次执行了登录操作,然后主动推送一个提醒告诉第一个用户账号异地登录;2是当用户进行操作的时候发现自己的账号被挤掉了,有异地登录。关于这两个方案,第一种是比较具有实时性的但是还在探究中,下面重点说一说第二种方式。

2,实现第二种也比较简单,两个操作,一是在用户表中多加一个字段,用来存储登录用户的SessionId,因为每一个request请求都会对应一个唯一不重复的Sessionid,然后呢就是用拦截器技术了,对用户的操作进行拦截,在拦截器中首先是对登录页面的相关url请求进行放行,然后还有的就是登录校验的请求放行。最后再对用户进行过滤,(关于用户登录,在验证成功时,不仅要把用户存入Session中用于登录拦截的验证,还需要把Session的ID存入用户表中对应的Sessionid)对于此次请求的request可以获取到Session及其ID然后再根据这个ID与数据库中的Sessionid进行比较是否相同相同则通过放行,不同则提示下线跳转登录,因为在一次用户连接服务器操作中会存在一个Session只要Session不过期每次用户发起的操作的request的Session的id都是一致的所以会和登录时存入数据库中的id匹配,当有其他人通过其他设备再用同一个账号进行登录时会重新建立Session会刷新数据库中的Sessionid而自己的Sessionid还是不变的,但是数据库中的Session已经发生了改变,所以在拦截器中校验数据库中Sessionid是否一致时就会失败从而拦截用户操作达到单用户登录的功能,(关于Session的说明,当用户初次与服务器连接时会在服务器端创建一个Session,而之后用户发起的每一次操作request中都会携带这个Session的id而出现一些情况Session的失效,用户长时间没有与服务器之间进行操作,用户退出登录主动让Session失效,用户关闭浏览器,或者服务器重新启动)

下面是SpringMVC中拦截器的实现

public class SingleUserInterceptor implements HandlerInterceptor {
	@Autowired
	private userMapper mapper;
	public void afterCompletion(HttpServletRequest arg0,
	HttpServletResponse arg1, Object arg2, Exception arg3)
	throws Exception {
		// TODO Auto-generated method stub
	}
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
	Object arg2, ModelAndView arg3) throws Exception {
		// TODO Auto-generated method stub
	}
	public Boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
	Object arg2) throws Exception {
		String url = arg0.getRequestURI();
		//如果拦截到的是登录的页面的话放行
		if(url.indexOf("login.jsp")>=0||url.indexOf("new/login")>=0||url.indexOf("checkuser")>=0){
			return true;
		}
		//如果用户名存在放心(即登录放行)
		Integer user = (Integer) arg0.getSession().getAttribute("user");
		if(user!=null){
			String sessionid = mapper.getUserEntity(Integer.valueOf(user)).getSessionid();
			if(sessionid.equals(arg0.getSession().getId())){
				return true;
			} else{
				arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);
				arg1.setContentType("text/html; charset=utf-8");
				PrintWriter out = arg1.getWriter();
				out.println("<html>");
				out.println("<script>");
				out.println("alert('您的账号在别地登录,您被迫下线')");
				out.println("window.open ('" + arg0.getContextPath()
				+ "/new/login','_top');");
				out.println("</script>");
				out.println("</html>");
				// arg0.getRequestDispatcher("login.jsp").forward(arg0, arg1);
				return false;
			}
		}
		arg0.getRequestDispatcher("login.jsp").forward(arg0, arg1);
		return false;
	}
}

以上的代码即可实现当同一个用户多次登录时,第一个登录用户在进行操作时会被挤下线的功能,可以实现先提示账号异地登录,然后跳转登录页面的功能。此处需要说明这个简单的alert提示功能的要点如果这要想出现这个alert必须能够时能够让请求结束,然后response的打印功能输出那个alert的提示语句,所以注释掉的那句跳转语句不能有,有则不会出alert提示语句,因为你的操作没有正确的结束而是被转发或者重定向为其他操作了不论正确与否都是其他的action向页面的输出了,所以你的response打印语句就不会出现。所以正确的做法是:拦截请求不在放行(returnfalse),此时请求还是原来的请求,并不会跳转,而response回页面的打印信息则可以显示,至于跳转登录页面则可以用:out.println("window.open('"+arg0.getContextPath()+"/new/login','_top');");来实现即在response所输出的一段js中执行了一个action请求,指向登录页面。

通过上面的代码基本上已经算是实现了单用户登录的功能,但是会发现ajax请求的操作并没有能够在异地登录时指向登录页面也没有提示信息,先说明一下原因,因为你的ajax时在进行一个异步请求,而且也在处理器映射器中匹配到了请求的url所以它会视为请求成功(返回状态码为200)而上面的response打印的js语句则会变为success中请求成功的,返回值,大家可以尝试一下把上面的这句话:arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);注释掉。这时需要进行一些其他操作,首先就是刚刚提到的语句arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);他的功能是设置response返回的状态码,上面的设置表示将返回状态码504代表请求出错,此时ajax请求就不会再在success方法中响应,而是会响应ajax的error方法,所以只需要再在ajax的error中执行对应的方法即可例如:

 $.ajax({
  url:'new/msd2',
  success:function(a){
  alert(a);
  },
  error:function(rs){
  if(rs.status==504){
  document.write(rs.responseText);
  }
  }
  }); 

当ajax请求因为异地登录被拦截时通过设置arg1.setStatus(arg1.SC_GATEWAY_TIMEOUT);可以使请求的返回状态变为504出错,然后由error方法响应,当判断到状态是自己所设置的状态码时再document.write(rs.responseText);responseText即为拦截器中所向前台打印的js语句,而要这些语句能够执行则需要document.write();方法将那些代码写入dom让其生效,至此,所有的请求,异步ajax请求的单点登录基本都已实现。

留此文只记录关键代码及思想及操作的原理

总结

以上就是本文关于SpringMVC拦截器实现单点登录的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持。

(0)

相关推荐

  • SpringMVC 拦截器不拦截静态资源的三种处理方式方法

    SpringMVC提供<mvc:resources>来设置静态资源,但是增加该设置如果采用通配符的方式增加拦截器的话仍然会被拦截器拦截,可采用如下方案进行解决: 方案一.拦截器中增加针对静态资源不进行过滤(涉及spring-mvc.xml) <mvc:resources location="/" mapping="/**/*.js"/> <mvc:resources location="/" mapping=&quo

  • SpringMVC配置拦截器实现登录控制的方法

    SpringMVC读取Cookie判断用户是否登录,对每一个action都要进行判断.之前使用jstl标签在页面上判断session如果没有登录就使用如下代码跳转到登录页面. <c:if test="${sessionScope.login == null || sessionScope.login == false}"> <!-- 未登录 --> <c:redirect url="/login"/> </c:if>

  • 浅谈springMVC拦截器和过滤器总结

    拦截器: 用来对访问的url进行拦截处理 用处: 权限验证,乱码设置等 spring-mvc.xml文件中的配置: <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" x

  • springmvc拦截器登录验证示例

    一开始,学了拦截器与过滤器,咋一看两者有点像,实际上两者有很大的不同.就用拦截器和过滤器分别做了登录验证试验,这次先说拦截器.下面是自己实践的一个实例: 在spring-mvc.xml中配置拦截器: <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/*"/> <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 --> <bean

  • SpringMVC拦截器——实现登录验证拦截器的示例代码

    本例实现登陆时的验证拦截,采用SpringMVC拦截器来实现 当用户点击到网站主页时要进行拦截,用户登录了才能进入网站主页,否则进入登陆页面 核心代码 首先是index.jsp,显示链接 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String bas

  • 详解利用SpringMVC拦截器控制Controller返回值

    背景:需求是在Controller中方法没有实现时,返回模拟结果.主要用于项目初期前台跟后台的交互,Web项目就是在前台发出请求然后后台响应并返回结果.本示例利用拦截器和注解实现跳过执行方法直接返回定义结构的功能. 通过定义一个StringResult注解,在访问方法的时候返回StringResult中的内容.通过Debug注解来定义方法是否要返回StringResult中的内容. Debug默认为TRUE package com.tiamaes.dep.annotation; import j

  • SpringMVC拦截器实现单点登录

    单点登录的功能在实际的应用场景中还是很重要的,逻辑上我们也不允许一个用户同时在进行着两个操作,下面就来了解一下SpringMVC的单点登录实现 SpringMVC的拦截器不同于Spring的拦截器,SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet,所以只需要在DispatcherServlet上做文章即可,DispatcherServlet也没有代理,同时SpringMVC管理的Controller也不有代理. 1,先探究一个

  • 详解SpringMVC拦截器配置及使用方法

    本文介绍了SpringMVC拦截器配置及使用方法,分享给大家,具体如下: 常见应用场景 1.日志记录:记录请求信息的日志,以便进行信息监控.信息统计.计算PV(Page View)等. 2.权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面: 3.性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录): 4.通用行为:读取cookie得到用户信

  • 详解SpringMVC拦截器(资源和权限管理)

    本文主要介绍了SpringMVC拦截器,具体如下: 1.DispatcherServlet SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet. DispatcherServlet是前置控制器,配置在web.xml文件中的.拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller来处理.  所以我们现在web.xml中加入以下配置: <!-- 初始化 Dispatcher

  • 详解springmvc拦截器拦截静态资源

    springmvc拦截器interceptors springmvc拦截器能够对请求的资源路径进行拦截,极大的简化了拦截器的书写.但是,千万千万要注意一点:静态资源的放行. 上代码: <mvc:resources mapping="/resources/**" location="/static/resources" /> <mvc:resources mapping="/static/css/**" location=&quo

  • SpringMVC拦截器实现监听session是否过期详解

    本文主要向大家介绍了SpringMVC拦截器实现:当用户访问网站资源时,监听session是否过期的代码,具体如下: 一.拦截器配置 <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/user/login"/> <!-- 不拦截登录请求 --> <mvc:exclude-

  • springMVC拦截器HandlerInterceptor用法代码示例

    摘要:很多时候我们都会去修改其他同事的bug,甚至是已经离职的同事的bug,有时候我们点击页面去不着到后台对应的是哪个controller,针对这个问题,其实我们可以通过sprngmvc的拦截器来拦击用户的请求从而知道页面请求的是哪个class的哪个方法,当然这些打印日志信息肯能并不适合放在生产环境,或者这个拦截器也是非必要的.... 一.HandlerInterceptor用法 第一步:注册拦截器 <!-- 注册拦截器 --> <mvc:interceptors> <bea

  • Springmvc拦截器执行顺序及各方法作用详解

    实现HandlerInterceptor接口或者继承HandlerInterceptor的子类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ,下面讲实现其接口的写法,先看一下这个接口的三个方法. - 方法preHandle: 顾名思义,该方法将在请求处理之前进行调用,在controller之前执行.SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在

  • 如何基于ssm框架实现springmvc拦截器

    Springmvc拦截器用来拦截Controller层请求,可以在Controller方法执行前后做一些特定的业务逻辑处理.类似于AOP中的环绕通知.常用来做登录拦截,权限控制等. 1)写一个类,实现HandlerIntercept接口: /** * 登录拦截器 */ public class LoginInterceptor implements HandlerInterceptor { /** * 在控制层方法请求之前调用,返回一个boolean类型值 * 如果返回的true则放行,如果返回

  • SpringMVC 拦截器的使用示例

    简介 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.开发者可以自己定义一些拦截器来实现特定的功能. 过滤器 servlet规范中的一部分,任何java web工程都可以使用 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截 拦截器 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用 拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不

随机推荐