0

    SpringMVC拦截器登录之后重新回到之前的页面及未登录非法访问

    2023.08.06 | admin | 118次围观

    之前想着在后台去登陆的时候拿到之前页面的url但是不知道怎么拿,而且发现就算拿也是哪的是登录的uri不是登录之前的uri,然后就想着从页面上获取,在除了登录注册外的每个页面上都获取到访问的uri然后想办法存到session中,登录之后再取出来进行跳转。但是感觉有点麻烦啊!这样我每个页面都需要写一次,获取uri,然后在存到session中,想到为header.jsp是几乎是嵌在出登录注册之外的所有页面中的,然后我就想如果在header里面写的话,不就很方便了吗?可是发现这个页面就根本就显示不出uri,大概是因为header.jsp它没有被请求,所以我开始放弃在页面进行获取了。

    在这个过程中对URL和URI的区别有了点体会

    URL统一资源定位符,代表当前访问的实际地址。
     ${pageContext.request.requestURL}
     或者
     ${pageContext.request.getAttribute("javax.servlet.forward.request_uri")}
     结果:http://localhost:8080/BookShopSSM/WEB-INF/content/book/newBookMore.jsp
    URI统一资源标识符,代表的是请求的路径。
    ${requestScope['javax.servlet.forward.request_uri']}
    结果:/BookShopSSM/newBookMore
    获取uri后面的参数
    ${pageContext.request.queryString} 
    结果:currentPage=1 

    然后突然想到了过滤器和拦截器,说不定可以用这个。

    那到底使用过滤器还是拦截器呢?

    关于拦截器与过滤器使用场景、拦截器与过滤器的区别整理 - CSDN博客

    拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

    过滤器:是在javaweb中,你传入的request、response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求有的网站会被拦截怎么设置,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符.。

    拦截器与过滤器使用场景:

    spring Web MVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

    1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

    2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;

    3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

    4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。

    5、OpenSessionInView:如hibernate,在进入处理器打开Session,在完成后关闭Session。

    过滤器和拦截器的区别:

    1)拦截器是基于java的反射机制的,而过滤器是基于函数回调。

    (2)拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。

    (3)拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。

    (4)拦截器可以访问action上下文、值栈里的对象,而过滤器不能。

    (5)在action的生命周期中有的网站会被拦截怎么设置,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

    因为我使用的是Spring框架,Spring对拦截器提供了支持,所以我选用了拦截器。

    关于拦截器的使用

    这两篇文章对我的的参考价值很大

    Spring中利用拦截器控制登录及页面跳转 - CSDN博客

    Spring mvc interceptor配置拦截器 - CSDN博客

    利用拦截器拦截除登录注册之外的所有跳转页面的请求,然后获取到页面的uri和参数,存储到session中,在登录验证通过之后再将session中存储的路径取出来,利用请求转发进行跳转。

    在配拦截器的时候发现静态资源无法访问了,这些用exclude-mapping path进行排除就好了,重点在之后发现一个非常烧脑的问题请求方式不允许!

    因为我的action请求有get,也有post,但是请求转发使用的是post方式,不支持get方式。这就会造成405 method not allowed异常,所以又开始百度请求转发怎么设置请求方式,找了好久也没有找到,最后想到了使用重定向,重定向默认使用的是get方式进行跳转,OK。利用请求转发和重定向的这点区别,我就可以在拦截器中通过request.getMethod()得到请求的方式,然后存在域对象中,在登录验证通过之后根据method是get还是post来判断是使用请求转发还是重定向。

    package com.wjh.interceptor;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import com.wjh.bean.TUser;
    /**
     * 用户登录以后跳转回之前页面的拦截器
     * 拦截对象:
     * 除登录,注册之外的所有跳转页面的请求
     * 因为用户随时可能进行登录操作
     * @author 17976
     *
     */
    public class ForwardBeforeLoginInteceptor implements HandlerInterceptor {
         @Override
            public void afterCompletion(HttpServletRequest arg0,HttpServletResponse arg1, 
                    Object arg2, Exception arg3) throws Exception {
            }
            @Override
            public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
                Object arg2, ModelAndView arg3) throws Exception {
            }
            @Override
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                Object arg2) throws Exception {
                TUser user = (TUser) request.getSession().getAttribute("user");
                if(user == null){//说明用户当前没有登录,所以需要记录用户在未登录前访问的页面地址,然后等用户登录以后再跳回之前的页面
                    HttpSession session = request.getSession(true); 
                    String uri = request.getRequestURI();//拿到上一个页面地址
                    String path = uri.substring(request.getContextPath().length());//去掉项目地址长度的字符(因为我的默认项目地址是给出的)
                    String query = request.getQueryString();//得到参数
                    if(query == null) {
                        query="";
                    }
                    else {
                        query="?"+query;
                    }
                    String beforePath = path+query;
                    System.out.println(beforePath+"=====method"+request.getMethod());//测试用
                    session.setAttribute("beforePath", beforePath);
                    session.setAttribute("method", request.getMethod());//测试
                }
                return true;
            }
    }
    

    spring-mvc.xml中的配置

    <mvc:interceptors>
            
            
            
            <mvc:interceptor>
                
                <mvc:mapping path="/**" />
                
                <mvc:exclude-mapping path="" />
                <mvc:exclude-mapping path="index.jsp" />
                
                <mvc:exclude-mapping path="/toLogin" />
                <mvc:exclude-mapping path="/login" />
                <mvc:exclude-mapping path="/toRegist" />
                <mvc:exclude-mapping path="/regist" />
                
                <mvc:exclude-mapping path="/*.ajax" />
                <mvc:exclude-mapping path="/js/**" />
                <mvc:exclude-mapping path="/jslib/**" />
                <mvc:exclude-mapping path="/css/**" />
                <bean class="com.wjh.interceptor.ForwardBeforeLoginInteceptor" />
            mvc:interceptor>
                
            <mvc:interceptor>
                <mvc:mapping path="/user*"/>
                <bean class="com.wjh.interceptor.UnLoginInterceptor"/>
            mvc:interceptor>
        mvc:interceptors>
        
        <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver"
            p:prefix="/WEB-INF/content/" p:suffix=".jsp"
            p:viewClass="org.springframework.web.servlet.view.JstlView" />
        
        <mvc:default-servlet-handler />
        
        <mvc:resources location="/static/" mapping="/static/**" />
        <mvc:resources location="/css/" mapping="/css/**" />
        <mvc:resources location="/js/" mapping="/js/**" />

    @RequestMapping(value="login",method=RequestMethod.POST)
        public String login(TUser tuser,Model model,HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
            TUser user=userv.login(tuser);
    //      System.out.println("user"+user);
            System.out.println("request.getContextPath()"+request.getContextPath());
            if(user!=null) {
                model.addAttribute("user",user);
                String beforePath=(String)request.getSession().getAttribute("beforePath");
                String method=(String)request.getSession().getAttribute("method");
                if(beforePath!=null) {
                    //请求转发默认使用的是post方式,不支持get方式
                    if("POST".equals(method)) {
                        request.getRequestDispatcher(beforePath).forward(request, response);
                    }
                    //如果是GET方式,就使用重定向,重定向默认使用的是GET方式。request.getContextPath()获得项目地址BookShopSSM/
                    else {
                        response.sendRedirect(request.getContextPath()+beforePath);
                    }
                }
                return "user/afterLogin";
            }
            return "user/login";
        }

    做了控制登录之后跳回原来页面的拦截器,然后我就顺便把防止用户未登录非法访问的拦截器也做了,虽然我在做页面的时候设计的是如果当前用户未登录就不提供个人中心的访问,但是还是得防止用户通过url方式进行非法访问,直接通过浏览器输入url采用的是get方式进行访问,还有超连接也是get方式,其实这都是属于重定向吧!所以使用get方式是不可避免的,要避免也可以自己通过js进行设置请求方式但是这样就有点麻烦了,还有我觉得post方式也不是绝对安全的,目前还不太清楚。总之还是配上未登录就非法访问个人信息这个拦截器比较好。

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论