2017-04-04 65 views
0

我需要對servlet的一些方法應用認證過濾器。過濾器檢查在請求中作爲標題鍵傳遞的JWT的有效性。過濾servlet的一些方法

例如,會話端點具有POST(登錄,公共)和DELETE(註銷,需要身份驗證)方法。也許我可以將這兩個分解爲一個註銷和登錄servlet,但是如果我的資源端點需要auth來發布(創建),並且不需要auth來獲取,則不可能應用過濾器,併爲每個servlet創建兩個單獨的servlet方法是一個很大的應用程序管理的痛苦。

有沒有解決方案,只通過使用servlet沒有任何框架?

除此之外,在我將過濾器應用於「/ secure」路徑的情況下,這不是真的用戶不友好嗎? (要訪問說「安全」或「公開」的網址)。

回答

0

我最終創建了一個方法addPublicFilter(),它將過濾器PublicFilter應用於您作爲參數傳遞的路徑和方法。

public class PublicFilter implements Filter { 

    private FilterConfig filterConfig; 
    public static final String PUBLIC_METHODS = "com.example.access.PUBLIC_METHODS"; 
    static final String IS_PUBLIC = "com.example.access.IS_PUBLIC"; 

    public void init(FilterConfig filterConfig) throws ServletException { 
     this.filterConfig = filterConfig; 
    } 

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     final List<String> allowedMethods = Arrays.asList(filterConfig.getInitParameter(PUBLIC_METHODS).split(",")); 
     final String method = ((HttpServletRequest) request).getMethod(); 

     if (allowedMethods.contains(method)) request.setAttribute(IS_PUBLIC, true); 
     chain.doFilter(request, response); 
    } 

    public void destroy() {} 
} 

然後在碼頭我的方法:

private static void addPublicFilter(ServletContextHandler context, String path, String publicMethods) { 
    final FilterHolder holder = new FilterHolder(PublicFilter.class); 
    holder.setInitParameter(PublicFilter.PUBLIC_METHODS, publicMethods); 
    context.addFilter(holder, path, EnumSet.of(DispatcherType.REQUEST)); 
} 

,我把它叫做:

addPublicFilter(context, "/*", "OPTIONS"); 
addPublicFilter(context, "/user/*", "POST"); 
addPublicFilter(context, "/session", "POST,GET"); 
1

在servlet和過濾器規範中,我不知道有什麼方法根據請求類型(GET/POST/PUT/DELETE ...)實際進行映射。一種直接但干擾的方式是傳遞一個描述應該處理的請求類型的字符串。在這種情況下,如果請求不在這些類型中,那麼過濾器應該立即調用過濾器鏈中的下一個元素。

如果您不想更改認證過濾器,您可以想象一個包裹過濾器,它將實際過濾器的類作爲參數以及參數傳遞給實際過濾器。在這種情況下,包裹過濾器將:

  • 在初始化時,在初始化創建真實濾波器的一個實例它
  • 在濾波器時間測試是該請求是可接受的類型和
    • 如果不是直接調用FilterChain
    • 若是調用實濾波器與當前請求,響應和鏈

的包裝過濾可能的代碼可能是:

public class WrappingFilter implements Filter { 
    Filter wrapped; 
    List<String> methods; 

    @Override 
    public void init(final FilterConfig filterConfig) throws ServletException { 
     // process FilterConfig parameters "actual_filter" and "methods" 
     String classname = filterConfig.getInitParameter("actual_filter"); 
     String methodsString = filterConfig.getInitParameter("methods"); 
     methods = Arrays.asList(methodsString.split("|")); 
     try { 
      // create and initialize actual filter 
      Class<?> clazz = Class.forName(classname); 
      wrapped = (Filter) clazz.getConstructor().newInstance(); 
      wrapped.init(filterConfig);    
     } catch (ClassNotFoundException ex) { 
      throw new ServletException(ex); 
     } catch (NoSuchMethodException ex) { 
      throw new ServletException(ex); 
     } catch (SecurityException ex) { 
      throw new ServletException(ex); 
     } catch (InstantiationException ex) { 
      throw new ServletException(ex); 
     } catch (IllegalAccessException ex) { 
      throw new ServletException(ex); 
     } catch (IllegalArgumentException ex) { 
      throw new ServletException(ex); 
     } catch (InvocationTargetException ex) { 
      throw new ServletException(ex); 
     } 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     String method = ((HttpServletRequest) request).getMethod(); 
     if (methods.contains(method)) { 
      // appropriate method: call wrapped filter 
      wrapped.doFilter(request, response, chain); 
     } 
     else { 
      // directly pass request to next element in chain by-passing wrapped filter 
      chain.doFilter(request, response); 
     } 
    } 

    @Override 
    public void destroy() { 
     // destroys wrapped filter 
     wrapped.destroy(); 
    }  
} 

的WrappingFilter過濾器將在Web應用程序可以正常申報。應該通過直接在Java中初始化一個FilterConfig傳遞,或間接通過web.xml文件filter_params:

  • actual_filter:一個String:實際過濾器的類名由WrappingFilter
  • methods包裹給予方法爲處理與|分離,例如POST|DELETE
  • 其他參數將被傳遞的卷繞的過濾器的初始化

小心:未經測試...

+0

我不明白它是如何可能增加一個過濾器(包過濾器),以一個特定的servlet傳遞一個字符串來描述該特定servlet中的哪些方法應該被認證。那是你的想法吧? FilterConfig可能? – niklabaz

+0

我正在遠離XML,並且以編程方式將過濾器添加到上下文中。 – niklabaz

0

如果你只是需要它的身份驗證,也許你不必編寫一個servlet過濾器。通過web.xml或通過@ServletSecurity指定SecurityConstraint,您可以限制某些http方法的約束。見例如herethere

但是如果你確實需要編寫一個過濾器,我知道的唯一方法是在你的過濾器實現中使用httpRequest.getMethod()來檢查http方法,參見eg。 this answer

+0

假設我@ServletSecurity會話servlet說DELETE方法只能通過驗證請求訪問。唯一的方法是通過角色?如果請求只有一個json Web令牌,我無法理解如何讓servlet檢測角色。 – niklabaz