自定义过滤器下拉向导,包含数

时间:2014-04-22 14:22:26

标签: database filter dropwizard

我使用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)〜[hibernate-core-4.3.1.Final.jar:4.3.1.Final]

4 个答案:

答案 0 :(得分:10)

启用DropWizard" magic" (Hibernate)在代码的非托管部分,你必须注入一个SessionFactory。您可以在DropWizard配置中看到如何创建一个:

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

然后,您可以将该sessionFacotry注入构造函数中的AuthenticationFilter。

在过滤器中,您必须手动绑定hibernate会话,例如:

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


}

这是本质。 bind()和close()之间发生的任何事情都会启用DropWizard魔法 - 也可以在托管Dao中使用。你可以通过使错误处理等更加健壮来改进它。

即使您正在点击示例中的托管资源,这也会有效。发生的事情是DropWizards RequestDispatcher激活并执行相同的操作:它打开一个会话并将其绑定到该线程。结果是托管资源使用的是另一个会话,而不是手动打开的会话,并且删除了最初绑定的会话而不进行清理。在你的例子中,THIS的效果是在调用doFilter(...)之后魔术已经结束。如果您以后要访问数据库,则必须重新绑定之前创建的会话。请致电:

        ManagedSessionContext.bind(session);

我还没有遇到过这项技术的任何问题,但是如果您需要在另一个会话中进行的一个会话中访问数据,我可以想象一个问题。这可能需要对隔离级别进行一些调整。

答案 1 :(得分: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();

这是否是最好的解决方案是值得商榷的,但就我的目的来说,这已经足够了。

答案 2 :(得分: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;
    }
}

在run-method中你可以添加:

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

此拉取请求https://github.com/dropwizard/dropwizard/pull/541可能会满足您的需求。

答案 3 :(得分:0)

在事务外使用AuthenticationDAO时会出现问题。如DropWizard manual中所述,注释@UnitOfWork可用于创建事务边界。

然而,为了使这项工作适用于泽西资源以外的课程,您需要使用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 {
        ...