【问题标题】:request.getRequestURI always returns "/error"request.getRequestURI 总是返回“/error”
【发布时间】:2017-05-14 12:35:53
【问题描述】:

在我正在使用 Spring Boot 和 MVC 构建的 web 应用程序中,我试图拒绝对除 /signin 之外的所有 URL 的访问,以供未登录的用户访问。为此,我设置了 HandlerInterceptor 的实现,其中 preHandler应该将所有无效请求路由到 /signin 页面。

设置:

LoginViewController

package com.controller;

import com.model.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping(value = "/signin")
@SessionAttributes("username")
public class LoginViewController {
    @Autowired
    private UserService userService;

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView showLoginForm(){
        return new ModelAndView("login");
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView verifyLogin(HttpServletRequest request, HttpSession session) {
        ModelAndView modelAndView;
        String username = request.getParameter("username");
        // if login fails, set reload login page
        if (userService.verifyUserLogin(username,request.getParameter("password")) == null){
            modelAndView = new ModelAndView("login");
            modelAndView.addObject("login_failed", true);
        } else {
            modelAndView = new ModelAndView("index");
            session.setAttribute("username", username);
        }
        return modelAndView;
    }
}

访问拦截器

package com.spring.interceptor;

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

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;

public class AccessInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {
        System.out.println(request.getRequestURI());

        try {
            if (!request.getRequestURI().endsWith("/signin")) {
                if (request.getSession()
                        .getAttribute("username") == null) {
                    response.sendRedirect(request.getContextPath() + "/signin");
                    return false;
                }

            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("After completion handle");
    }
}

WebApplicationConfig

package com.spring;

import com.spring.interceptor.AccessInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;

@Configuration
@EnableWebMvc
public class WebApplicationConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(
                new AccessInterceptor()).
                addPathPatterns("/**").
                excludePathPatterns("/signin/**").
                excludePathPatterns("/static/**");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    }

}

WebApplicationInitializer

package com.spring;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;

public class MyWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext container) {
        // Create the 'root' Spring application context
        AnnotationConfigWebApplicationContext rootContext =
                new AnnotationConfigWebApplicationContext();
        rootContext.register(WebApplicationConfig.class);

        // Manage the lifecycle of the root application context
        container.addListener(new ContextLoaderListener(rootContext));

        // Create the dispatcher servlet's Spring application context
        AnnotationConfigWebApplicationContext dispatcherContext =
                new AnnotationConfigWebApplicationContext();
        dispatcherContext.register(MyWebAppInitializer.class);

        // Register and map the dispatcher servlet
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcherServlet", new DispatcherServlet(rootContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/*");
        dispatcher.addMapping("*.css");
        dispatcher.addMapping("*.eot");
        dispatcher.addMapping("*.svg");
        dispatcher.addMapping("*.ttf");
        dispatcher.addMapping("*.woff");
        dispatcher.addMapping("*.map");
        dispatcher.addMapping("*.js");
        dispatcher.addMapping("*.ico");
    }

}

现在的问题是 AccessInterceptor 中的System.out.println(request.getRequestURI()) 总是打印/error。所以即使调用/signin,请求也会被重定向。另一个有趣的事情是,即使配置了调度程序映射,也不会呈现 CSS 或其他静态资源。

有什么想法吗?

【问题讨论】:

  • 我有同样的问题...所有路径匹配器都因此而无法工作(我认为)。你找到解决办法了吗?
  • 您好!从那以后已经有一段时间了,但据我所知,我从未真正解决过这个问题。我认为我完全放弃了使用 MVC 结构并以 RESTful 方式进行操作。对不起,我帮不上忙,但如果你找到答案,请分享。我仍然很感兴趣:)
  • 我发现 spring-security 是问题所在,但我仍然不知道确切的问题是什么......我正在制作一个 RESTful 应用程序。

标签: java spring spring-mvc spring-boot interceptor


【解决方案1】:

如果您丢失了有效载荷,api url 将无法识别。至少放点东西

【讨论】:

    【解决方案2】:

    我也遇到过这个问题,在 WebLogIntercept(your MyWebAppInitializer) 类中 我使用以下代码解决了这个问题

    添加这两个函数

        private Class getClassByName(Class classObject, String name){
            Map<Class,List<Field>> fieldMap = new HashMap<>();
            Class returnClass = null;
            Class tempClass = classObject;
            while (tempClass != null) {
                fieldMap.put(tempClass,Arrays.asList(tempClass .getDeclaredFields()));
                tempClass = tempClass.getSuperclass();
            }
    
            for(Map.Entry<Class,List<Field>> entry: fieldMap.entrySet()){
                for (Field f : entry.getValue()) {
                    if(f.getName().equals(name)){
                        returnClass = entry.getKey();
                        break;
                    }
                }
            }
            return returnClass;
        }
    
        private Object findCoyoteRequest(Object request)  throws Exception {
            Class a = getClassByName(request.getClass(),"request");
            Field request1 = a.getDeclaredField("request");
            request1.setAccessible(true);
            Object b = request1.get(request);
            if(getClassByName(b.getClass(),"coyoteRequest") == null){
                return findCoyoteRequest(b);
            }else{
                return b;
            }
    

    并使用此代码

    Object a = findCoyoteRequest(request);
    Field coyoteRequest = a.getClass().getDeclaredField("coyoteRequest");
    coyoteRequest.setAccessible(true);
    Object b = coyoteRequest.get(a);
    
    Field uriMB = b.getClass().getDeclaredField("uriMB");
    uriMB.setAccessible(true);
    MessageBytes c = (MessageBytes)uriMB.get(b);
    System.out.println(c.getString());
    

    c.getString() 是真实的

    我的英文不好,希望有用

    【讨论】:

      【解决方案3】:

      禁用 CFR 对我有用 见https://www.baeldung.com/spring-security-csrf

      @Override
      protected void configure(HttpSecurity http) throws Exception {
         http.csrf().disable();
      }
      

      【讨论】:

        【解决方案4】:

        我有和你一样的功能。我终于发现这个功能没有任何问题。 “/error”请求实际上存在,可能是由 servlet 容器或其他(我不知道)发送的。它的存在是为了向您显示浏览器上的异常。 当我将“/error”添加到我的白名单(我还添加了不需要权限的“/login”之类的路径)时,e.printStackTrace(); 信息只会显示在浏览器上。

        【讨论】:

          【解决方案5】:

          有时,你可以尝试重建项目,这是我的代码:

          if(request.getRequestURI().startsWith("/user/")) {return true;}

          它总是返回“/error

          【讨论】:

          • 这没有提供问题的答案。
          • 问题的解决方案在哪里?它对你有用,但对他不起作用,重建并不能解决问题
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-09-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多