使用session和SpringMVC拦截器实现登录权限认证

在之前的博文里,我解决了前端和后台的通讯问题,也解决了Ajax取得验证结果后直接跳转到主页面的问题,在实际的使用后,我又发现了一个问题:登录后可以跳转至主页面,这很合理,但没有登录的人也可以访问主页面,这就有点尴尬了。

所以现在的问题是,如何才能阻止那些没有登录的人访问主页面呢

开门的钥匙

经过一段时间的学习,我发现了一种被称为session的东西。它由服务器生成,由服务器保存,可以用来识别出那些已经登录的人。举个例子,用户A登录后,服务器给他生成一条他自己独有的session,他每次尝试访问主页时,服务器都会检查他之前是否获得过session,如果没有session,说明他是没有登录过的人,必须将他重定向到登录页面。

所以,session是一种开门的钥匙,拥有session的人才有资格访问主页面。

SpringMVC的审核门

既然我们使用session机制可以识别已经登录的人,那么SpringMVC中有没有什么关卡,可以将那些没有钥匙的人挡在外面?

答案是:有,拦截器!拦截器可以审核URL请求,合法的就放行让服务器进行响应,不合法的就拦下来。

session的使用

在接受登录请求的控制器里,当用户的密码正确时,在代码里加入两行:

1
2
httpSession.setAttribute(StudentConst.STUDENT_EMAIL, email);
httpServletResponse.addCookie(new Cookie(StudentConst.STUDENT_EMAIL, email));

它会在服务器中为该用户生成一条键为StudentConst.STUDENT_EMAIL(该常量代码的字符串是“EMAIL”)值为email变量所指向字符串的session,同时也命令浏览器生成相应的cookie来保存session。

如此一来,登录过的用户就拥有session记录了,没登录的自然没有。

在拦截器里,我们将“是否拥有session”作为审核通过的唯一因素,就能将未登录的人挡在门外咯。

拦截器的使用

首先我们在Spring的WEB层配置文件(spring-web.xml)中声明一个拦截器的拦截范围:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<mvc:interceptors>
<mvc:interceptor>
<!--拦截以localhost:8080/student/开头的URL请求,包括localhost:8080/student/dashboard和localhost:8080/student/dashboard/detail类型-->
<mvc:mapping path="/student/**"/>
<!--排除在拦截名单外的URL请求-->
<!--首先是注册请求,这个在任何时候都不能拦截-->
<mvc:exclude-mapping path="/student/register"/>
<!--然后是登录请求-->
<mvc:exclude-mapping path="/student/login"/>
<!--下面的是一些资源文件,比如图片、CSS文件、JS文件等-->
<mvc:exclude-mapping path="/student/common/**"/>
<mvc:exclude-mapping path="/student/css/**"/>
<mvc:exclude-mapping path="/student/js/**"/>
<!--当有URL被拦截后,调用下面这个拦截器StudentSessionInterceptor来处理,StudentSessionInterceptor决定了是放行还是拦截-->
<bean class="com.ilovecl.interceptor.StudentSessionInterceptor"/>
</mvc:interceptor>

当用户请求localhost:8080/student/dashboard时就将该请求转交给StudentSessionInterceptor进行处理,该拦截器的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.ilovecl.interceptor;

import com.ilovecl._const.StudentConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 登录验证的拦截器
*
* @author qiuyongchen
* email:qiuych3@mail2.sysu.edu.cn
* copyRight:The MIT License (MIT)
* @since 2016-06-01 20:18
*/
public class StudentSessionInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
Object email = httpServletRequest.getSession().getAttribute(StudentConst.STUDENT_EMAIL);
if (email == null) {
logger.info("用户尚未登录,将其重定向至登录页面");
httpServletResponse.sendRedirect("/student/login");
return false;
}
return true;
}

@Override
public void postHandle(HttpServletRequest hsr, HttpServletResponse hsr1, Object o, ModelAndView mav) throws Exception {
}

@Override
public void afterCompletion(HttpServletRequest hsr, HttpServletResponse hsr1, Object o, Exception excptn) throws Exception {
}

}

拦截器里有个名为preHandle的方法,它在服务器处理URL请求之前,先审核URL请求,以便决定是否进行拦截。如果该用户没有session,那就将其重定向httpServletResponse.sendRedirect("/student/login");,并返回false表示不放行,否则返回true表示放行。