简单的登录权限验证实现
1.登录
登录时需要生成一个自定义的token,token的生成规则一般可以考虑混合多种因素,如userId+生成时间+UUID,再进行一定的编码
String token=userId+UUID.randomUUID().toString(); 然后将生成的token放入session request.getSession().setAttribute("token", token); 并将该token管理起来 public static Map<String, String> userLoginInfoMap = new ConcurrentHashMap<String, String>(); loginMap.put(session.getId(), token);
2.设置session的过期时间
在web.xml中加入
<listener> <listener-class>com.project.listener.SessionListener</listener-class> </listener> <!-- session超时定义,单位为分钟 --> <session-config> <session-timeout>1440</session-timeout> <!--1440分钟(1天)后失效 --> </session-config>
project自行修改为当前项目名
在session过期时清除map
package com.project.listener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class SessionListener implements HttpSessionListener { //Session创建时的方法 public void sessionCreated(HttpSessionEvent event) { } public void sessionDestroyed(HttpSessionEvent event) { HttpSession session = event.getSession(); synchronized (this) { loginMap.remove(session.getId()); } } }
3.使用Filter过滤请求,使未登录用户自动跳转到登录页
<!-- Filter过滤未授权用户 --> <filter> <filter-name>LoginFilter</filter-name> <filter-class>com.project.filter.LoginFilter</filter-class> <!-- 定义Filter过滤的忽略列表 --> <init-param> <param-name>ignores</param-name> <param-value>/login.jsp</param-value> </init-param> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping>
拦截所有的jsp页面请求,这里login.jsp登录页本身设置成不能被拦截
package com.project.filter; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils; public class LoginFilter extends HttpServlet implements Filter { private static final long serialVersionUID = 1L; private Set<String> prefixIignores = new HashSet<String>(); public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; String url = request.getRequestURI(); // 过滤忽略列表 for (String ignore : prefixIignores) { if (url.startsWith(ignore)) { arg2.doFilter(request, response); return; } } HttpSession session = request.getSession(); String token = (String)session.getAttribute("token"); if (StringUtils.isNotBlank(token) && loginMap.get(session.getId()) == token) { arg2.doFilter(request, response); } else { // 判断获取的路径不为空且不是访问登录页面或执行登录操作时跳转 if (url != null && !url.equals("") && (url.indexOf("Login") < 0 && url.indexOf("login") < 0)) { //重定向到登录页 //response.sendRedirect(request.getContextPath() + "/login.jsp"); //使用重定向无法解决在iframe中跳转的问题,所以使用window.top.location跳转 response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8");// 防止弹出的信息出现乱码 String loginUrl="http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath()+"/login.jsp"; //登录页URL PrintWriter out = response.getWriter(); out.print("<script>alert('登录信息已失效!')</script>"); out.print( "<script>window.top.location="+"\""+loginUrl+"\""+"</script>"); out.flush(); out.close(); } } return; } public void init(FilterConfig config) throws ServletException { if (config == null) { return; } // 初始化忽略列表 String cp = config.getServletContext().getContextPath(); String ignoresParam = config.getInitParameter("ignores"); String[] ignoreArray = ignoresParam.split(","); for (String s : ignoreArray) { prefixIignores.add(cp + s); } } }
在filter的init-param中设置的页面将不被拦截,加入到prefixIignores忽略列表,在doFilter拦截到的页面先判断是否是忽略列表,如果是的话就不拦截,不是的话再进行后续拦截,当检测到token无效时引导用户跳转到登录页重新登录,这里不使用重定向的方式,因为当在iframe中进行重定向跳转时,外部顶层页面并不会进行跳转。