RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 648409
Accepted
JVic
JVic
Asked:2020-04-05 00:48:07 +0000 UTC2020-04-05 00:48:07 +0000 UTC 2020-04-05 00:48:07 +0000 UTC

@WebFilter( UrlPatterns = {""}) 被忽略

  • 772

我有点不明白,urlPatterns过滤器应该如何工作?为什么不管 url 是什么,过滤器都可以正常工作?

@WebFilter(urlPatterns = {"/groups/*"})
public class AuthorizationFilter implements Filter {

    @Autowired
    UserService service;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;   

        filterChain.doFilter(request,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

....
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        return new Filter[] { characterEncodingFilter,new AuthorizationFilter()};
    }
....
java
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    Sergey Gornostaev
    2020-04-07T14:28:22Z2020-04-07T14:28:22Z

    @WebFilter是一个非 Spring 注释,因此 Spring 会简单地忽略它。如果没有 DispatcherServletInitializer方法, getServletFiltersWeb 应用程序甚至不会注意到过滤器。但它只getServletFilters()返回一个过滤器数组,没有绑定到 URL。所以他们会为任何请求工作。有几种方法可以摆脱这种情况。

    首先,您可以将地址映射到 web.xml 中的过滤器:

    <filter>
      <filter-name>authFilter</filter-name>
      <filter-class>com.example.AuthorizationFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>authFilter</filter-name>
      <url-pattern>/groups/*</url-pattern>
    </filter-mapping>
    

    其次,您可以使用原生的 Spring HandlerInterceptor。没错,他们不会简化代码。您将不得不不再在部署描述符中编写绑定,而是在上下文配置中编写绑定,这不会摆脱 xml 并且不会简化它,或者在代码中配置它们:

    public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
            // Логика
        }
    }
    
    @Configuration
    @ComponentScan("com.example")
    @EnableWebMvc  
    public class AppConfig extends WebMvcConfigurerAdapter  {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry
              .addInterceptor(new AuthorizationInterceptor())
              .addPathPatterns("/groups/*");
        }
    }
    
    public class WebAppInitializer implements WebApplicationInitializer {
        public void onStartup(ServletContext servletContext) throws ServletException {  
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();  
            ctx.register(AppConfig.class);  
            ctx.setServletContext(servletContext);    
            Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));  
            dynamic.addMapping("/");  
            dynamic.setLoadOnStartup(1);  
       }  
    }
    

    但是您可以通过在注释上发明自行车来稍微简化此选项:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface AuthRequired {}
    
    public class AuthorizationInterceptor extends HandlerInterceptorAdapter { 
        @Override 
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
            HandlerMethod hm = (HandlerMethod) handler; 
            Method method = hm.getMethod();
            if (method.getDeclaringClass().isAnnotationPresent(Controller.class)) {
                if (method.isAnnotationPresent(AuthRequired.class)) { 
                    // Логика
                }
            } 
            return true; 
        }
    }
    
    @Controller
    public class SimpleController {
        @RequestMapping(path = "/", method = RequestMethod.GET)
        public String index() {
            // Логика
        }
    
        @RequestMapping(path = "/groups/{groupName}", method = RequestMethod.GET)
        @AuthRequired
        public String group(@PathVariable String groupName) {
            // Логика
        }
    }
    

    剩下的就是在上下文配置中注册拦截器

    <beans>
      <mvc:interceptors>
        <bean class="com.example.AuthorizationInterceptor" />
      </mvc:interceptors>
    </beans>
    

    而且它只适用于标有适当注释的方法。使用这辆自行车,部署描述符和上下文配置非常简单,根本不需要初始化程序。

    但是,您甚至可以堆积自己的注释模拟@WebFilter!首先,我们需要另一辆自行车来检查模式:

    public class GlobMatcher {
        public static boolean match(String pattern, String text) {
            String rest = null;
            int pos = pattern.indexOf('*');
            if (pos != -1) {
                rest = pattern.substring(pos + 1);
                pattern = pattern.substring(0, pos);
            }
    
            if (pattern.length() > text.length())
                return false;
    
            for (int i = 0; i < pattern.length(); i++)
                if (pattern.charAt(i) != '?' 
                        && !pattern.substring(i, i + 1).equalsIgnoreCase(text.substring(i, i + 1)))
                    return false;
    
            if (rest == null) {
                return pattern.length() == text.length();
            } else {
                for (int i = pattern.length(); i <= text.length(); i++) {
                    if (match(rest, text.substring(i)))
                        return true;
                }
                return false;
            }
        }
    }
    

    自己的 WebFilter 注释与俄罗斯方块和程序员:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface WebFilter {
        String[] urlPatterns();
    }
    

    和一个稍微修改的扰流板:

    @WebFilter(urlPatterns = {"/groups/*"})
    public class AuthorizationInterceptor extends HandlerInterceptorAdapter { 
        @Override 
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
            Class cls = getClass();
            if (cls.isAnnotationPresent(WebFilter.class)) {
                String[] patterns = ((WebFilter) cls.getAnnotation(WebFilter.class)).urlPatterns();
                for (String pattern : patterns) {
                    if (GlobMatcher.match(pattern, request.getRequestURI())) {
                        // Логика
                    }
                }
            }
            return true; 
        }
    }
    

    为了不弄脏带有端到端功能的代码,您可以创建一个方面来检查当前 URL 是否与模式匹配:

    @Aspect
    public class WebFilterAspect {
        @Pointcut("within(@com.example.WebFilter *)")
        public void beanAnnotatedWithWebFilter() {}
    
        @Pointcut("execution(boolean com.example..preHandle(..))")
        public void preHandleMethod() {}
    
        @Pointcut("preHandleMethod() && beanAnnotatedWithWebFilter()")
        public void preHandleMethodInsideAClassMarkedWithWebFilter() {}
    
        @Around("preHandleMethodInsideAClassMarkedWithWebFilter()")
        public Object beforeFilter(ProceedingJoinPoint joinPoint) throws Throwable {
            Object[] args = joinPoint.getArgs();
            if(args.length > 0) {
                HttpServletRequest request = (HttpServletRequest) args[0];
                Class target = joinPoint.getTarget().getClass();
                if (target.isAnnotationPresent(WebFilter.class)) {
                    String[] patterns = ((WebFilter) target.getAnnotation(WebFilter.class)).urlPatterns();
                    for (String pattern : patterns) {
                        if (GlobMatcher.match(pattern, request.getRequestURI())) {
                            return joinPoint.proceed();
                        }
                    }
                }
            }
            return true;
        }
    }
    

    然后剧透简化为:

    @WebFilter(urlPatterns = {"/groups/*"})
    public class AuthorizationInterceptor extends HandlerInterceptorAdapter { 
        @Override 
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 
            // Логика
            return true; 
        }
    }
    
    • 2
  2. Mike Lyubimtsev
    2020-04-16T01:43:57Z2020-04-16T01:43:57Z

    要从 Servlet 访问 Spring Beans,您可以创建一个包装器类,从中request继承调用方法。 ( https://stackoverflow.com/a/17490865/9967010 )HttpServletRequestWrapperSpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)

    @WebFilter("/groups/*")
    public class AuthorizationFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;   
    
            AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(request, response);
    
            if(foo(response) || authenticatedRequest.foo()) {
                filterChain.doFilter(authenticatedRequest, servletResponse);
            } else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "error message");
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }
    
    public class AuthenticatedRequest extends HttpServletRequestWrapper {
    
        @Autowired
        UserService service;
    
        public AuthenticatedRequest(HttpServletRequest request, HttpServletResponse response) {
            super(request);
    
            if (service==null) {
               SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
            }
            ...
        }
    
        @Override
        public Principal getUserPrincipal() {
            return () -> service.getCurrentUserName();
        }
        ...
    }
    
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5