Custom filter drop wizard with database information

database, dropwizard, filter

Solution

To enable the DropWizard "magic" (Hibernate) in non-managed parts of your code, you'll have to inject a SessionFactory. You can see how to create one in the DropWizard configuration:

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

Then you can inject that sessionFacotry into your AuthenticationFilter in the constructor.

In the filter you'll have to manually bind the hibernate session, like:

@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.


}

This is the essense. Anything happening between the bind() and close() will have DropWizard magic enabled - also in the managed Dao's. You could refine it by making it more robust with error handling etc.

This works even if you are hitting a managed resource like the one in your example. What happens is that the DropWizards RequestDispatcher activates and do the same thing, you do: it opens a session and bind it to the thread. The effect is that the managed resource uses another session than the one you opened manually AND that the one you originally bound is removed without cleanup. The effect of THIS in your example is that the magic has ended after the call to doFilter(...). If you want to access the database hereafter, you'll have to rebind the session you created before. Just call:

        ManagedSessionContext.bind(session);

I haven't experienced any problems with the technique, but one place I could imagine issues would be if you need to access data in one session made in another session. This could require some tweaking with isolation levels.

Problem

I'm using dropwizard 0.7.0 and I would like to create a custom filter. The custom filter should check if a token exists in the database. What is the correct way to create the filter and register this filter in the Application class? I used this question to implement the filter, this is working but when I change the code to this: ``` final AuthenticationDAO authenticationDAO = new AuthenticationDAO(hibernateBundle.getSessionFactory()); environment.servlets().addFilter("authenticationFilter", new AuthenticationFilter(authenticationDAO)).addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/transaction/*"); ``` This is my filter: ``` 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() { } } ``` When the filter will be accessed, I get the error below because there is no session active: WARN [2014-04-22 14:37:42,733] org.eclipse.jetty.servlet.ServletHandler: /test/show ! org.hibernate.HibernateException: No session currently bound to execution context ! at org.hibernate.context.internal.ManagedSessionContext.currentSession(ManagedSessionContext.java:75) ~[hibernate-core-4.3.1.Final.jar:4.3.1.Final] ! at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1013) ~[hibernate-core-4.3.1.Final.jar:4.3.1.Final]

Original source

Related problems