简单的登录权限验证实现

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中进行重定向跳转时,外部顶层页面并不会进行跳转。

posted @ 2017-05-20 11:59  桔子在路上  阅读(1135)  评论(0编辑  收藏  举报