2014-04-22 16 views
3

我正在使用dropwizard 0.7.0,我想創建一個自定義篩選器。帶數據庫信息的自定義篩選器下拉向導

定製過濾器應檢查數據庫中是否存在令牌。 創建過濾器並在Application類中註冊該過濾器的正確方法是什麼?

我以前this question實現過濾器,這是工作,但是當我更改代碼這樣:

final AuthenticationDAO authenticationDAO = new AuthenticationDAO(hibernateBundle.getSessionFactory()); 
environment.servlets().addFilter("authenticationFilter", new AuthenticationFilter(authenticationDAO)).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/transaction/*"); 

這是我的過濾器:

public class AuthenticationFilter implements Filter { 

    private final AuthenticationDAO authenticationDAO; 

    public AuthenticationFilter(AuthenticationDAO authenticationDAO) { 
     this.authenticationDAO = authenticationDAO; 
    } 

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

    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 
     String authenticationToken = ((Request) servletRequest).getHeader(Constants.HEADER_TOKEN_PARAM_NAME); 

     HttpServletResponse response = (HttpServletResponse)servletResponse; 

     if(Strings.isNullOrEmpty(authenticationToken)){ 
      response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
     } else if(!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()){ 
      response.setStatus(HttpServletResponse.SC_FORBIDDEN); 
     } else { 
      filterChain.doFilter(servletRequest, servletResponse); 
     } 
    } 

    @Override 
    public void destroy() { 
    } 
} 

當過濾器將被訪問,我得到下面的錯誤,因爲沒有會話活動:

WARN [2014-04-22 14:37:42,733] org.eclipse.jetty.servlet.ServletHandler:/ test/show ! org.hibernate.HibernateException:沒有會話當前綁定到執行上下文 !在org.hibernate.context.internal.ManagedSessionContext.currentSession(ManagedSessionContext.java:75)〜[hibernate-core-4.3.1.Final.jar:4.3.1.Final] !在org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1013)〜[休眠 - 核心4.3.1.Final.jar:4.3.1.Final]

回答

0

也許你可以試試:

import com.google.common.base.Strings; 
import com.sun.jersey.spi.container.ContainerRequest; 
import com.sun.jersey.spi.container.ContainerRequestFilter; 

import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.Response; 

public class AuthenticationFilter implements ContainerRequestFilter { 
    private final AuthenticationDAO authenticationDAO; 

    public AuthenticationFilter(AuthenticationDAO authenticationDAO) { 
     this.authenticationDAO = authenticationDAO; 
    } 

    @Override 
    public ContainerRequest filter(final ContainerRequest containerRequest) { 
     String authenticationToken = containerRequest.getHeaderValue(Constants.HEADER_TOKEN_PARAM_NAME); 

     if (Strings.isNullOrEmpty(authenticationToken)) { 
      throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); 
     } else if (!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()) { 
      throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN).build()); 
     } 
     return containerRequest; 
    } 
} 

和運行方法,你可以添加:

environment.jersey().getResourceConfig().getContainerRequestFilters().add(new AuthenticationFilter(...)); 

這種上拉的要求,https://github.com/dropwizard/dropwizard/pull/541,可能包括你的需求。

+0

感謝您的回答,但這不是正確的答案,我應該添加一個url模式。該解決方案不會訪問過濾器。 –

+0

我已經更新了我的答案。我自己使用這個解決方案。 – user2720917

+0

訪問令牌檢查時也出現錯誤: org.hibernate.HibernateException:沒有會話當前綁定到執行上下文 –

1

我這個打自己,我想我的問題是,在第Dropwizard線程討論: https://groups.google.com/forum/#!msg/dropwizard-user/LE6FYIpSDQ0/X5smCEZWltcJ

總之,你可能需要打開並綁定自己的會話 - 我的班由Dropwizard管理正在使用會話很好,但不通過dropwizard管理的類會遇到此錯誤。

我試圖決定打開和綁定我自己的會話,只是將類移動到Dropwizard管理的類,以便我可以使用@UnitOfWork註釋。

添加到此 - 如果您不在@UnitOfWork中(它似乎只對其他調用有效),那麼您可以使用會話就好 - 但不能使用DAO層。如果你使用DAO,你會得到這個錯誤。可能有更多的這一點,但我的目的,我只是用SQLQuery對:

 SQLQuery deleteQuery = session.createSQLQuery("DELETE FROM MYTABLE WHERE REPORTTIME < ?"); 
     deleteQuery.setTimestamp(0, cutoffDate.toDate()); 
     deleteQuery.executeUpdate(); 

這是否是最好的解決方案是值得商榷的,但對於我而言這是相當足夠的。

10

要在代碼的非託管部分啓用DropWizard「魔術」(Hibernate),您必須注入一個SessionFactory。你可以看到如何在DropWizard配置創建一個:

https://dropwizard.github.io/dropwizard/manual/hibernate.html

然後你可以注入該sessionFacotry到在構造函數中的AuthenticationFilter。

在過濾器中,你必須手動綁定Hibernate的Session,如:

@Override 
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 
    String authenticationToken = ((Request) servletRequest).getHeader(Constants.HEADER_TOKEN_PARAM_NAME); 

     Session session = sessionFactory.openSession(); 
     session.setDefaultReadOnly(true); 
     session.setCacheMode(CacheMode.NORMAL); 
     session.setFlushMode(FlushMode.MANUAL); 
     ManagedSessionContext.bind(session); 
     // DropWizard magic enabled from this point. 

    HttpServletResponse response = (HttpServletResponse)servletResponse; 

    if(Strings.isNullOrEmpty(authenticationToken)){ 
     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 
    } else if(!authenticationDAO.findByAuthenticationToken(authenticationToken).isPresent()){ 
     response.setStatus(HttpServletResponse.SC_FORBIDDEN); 
    } else { 
     filterChain.doFilter(servletRequest, servletResponse); 
    } 

     session.close(); 
     // DropWizard magic disabled from this point. 


} 

這是essense。在bind()和close()之間發生的任何事情都會啓用DropWizard魔法 - 也是在託管的Dao中。您可以通過使錯誤處理更加穩健,從而使其更加精確。

即使您正在訪問示例中的受管資源,也能正常工作。會發生什麼情況是DropWizards RequestDispatcher會激活並執行相同的操作,您可以這樣做:打開會話並將其綁定到線程。其效果是託管資源使用的另一個會話不是手動打開的會話,而是您最初綁定的那個會被刪除而不進行清理。在你的例子中,THIS的效果是魔法在調用doFilter(...)後結束了。如果您想在此後訪問數據庫,則必須重新綁定之前創建的會話。只要致電:

 ManagedSessionContext.bind(session); 

我沒有經歷過任何問題的技術,但是如果你需要在另一個會議上提出一個會話訪問數據的一個地方,我能想象到的問題會。這可能需要調整一些隔離級別。

+0

我也使用過這個來創建一個dropwizard任務時解決同樣的問題。 –

0

在事務外使用AuthenticationDAO時出現問題。如DropWizard manual中所述,註釋@UnitOfWork可用於創建事務邊界。

但是,爲了使Jersey Resources以外的其他類的工作成功,您需要使用UnitOfWorkAwareProxyFactory

首先創建一個工廠。

UnitOfWorkAwareProxyFactory proxyFactory = new UnitOfWorkAwareProxyFactory("session factory", hibernateBundle.getSessionFactory()); 

然後用它來創建AuthenticationFilter。

AuthenticationFilter filter = proxyFactory.create(AuthenticationFilter.class, AuthenticationDAO.class, authenticationDAO); 
environment.servlets().addFilter("authenticationFilter", filter).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/transaction/*"); 

最後用@UnitOfWork註釋doFilter。

public class AuthenticationFilter implements Filter { 
    @UnitOfWork 
    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 
     ...