Database 带有数据库信息的自定义筛选器删除向导

Database 带有数据库信息的自定义筛选器删除向导,database,filter,dropwizard,Database,Filter,Dropwizard,我正在使用dropwizard 0.7.0,我想创建一个自定义筛选器 自定义筛选器应检查数据库中是否存在令牌。 创建筛选器并在应用程序类中注册此筛选器的正确方法是什么 我曾经实现过过滤器,但当我将代码更改为以下内容时: final AuthenticationDAO authenticationDAO = new AuthenticationDAO(hibernateBundle.getSessionFactory()); environment.servlets().addFilter("au

我正在使用dropwizard 0.7.0,我想创建一个自定义筛选器

自定义筛选器应检查数据库中是否存在令牌。 创建筛选器并在应用程序类中注册此筛选器的正确方法是什么

我曾经实现过过滤器,但当我将代码更改为以下内容时:

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() {
    }
}
当访问筛选器时,由于没有活动的会话,我收到以下错误:

警告[2014-04-22 14:37:42733]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(sessionfactorympl.java:1013)~[hibernate-core-4.3.1.Final.jar:4.3.1.Final]

也许您可以尝试:

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方法中,您可以添加:

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

此拉取请求可能会满足您的需要。

我自己也遇到了这个问题,我认为我的问题与Dropwizard线程中讨论的一样:

简言之,您可能需要打开并绑定自己的会话—Dropwizard管理的my类使用的会话很好,但Dropwizard未管理的类遇到此错误

我正试图在打开和绑定我自己的会话之间做出决定,而只是将类移动到Dropwizard管理的会话,以便使用@UnitOfWork注释

此外,如果您不在@UnitOfWork中(它似乎只对rest调用有效),那么您可以很好地使用会话,但不能使用DAO层。如果您使用DAO,您将得到该错误。可能还有更多,但出于我的目的,我只使用了一个SQLQuery:

        SQLQuery deleteQuery = session.createSQLQuery("DELETE FROM MYTABLE WHERE REPORTTIME < ?");
        deleteQuery.setTimestamp(0, cutoffDate.toDate());
        deleteQuery.executeUpdate();
SQLQuery deleteQuery=session.createSQLQuery(“从我的表中删除,其中REPORTTIME<?”;
deleteQuery.setTimestamp(0,截止日期.toDate());
deleteQuery.executeUpdate();
这是否是最好的解决方案还存在争议,但就我而言,这已经足够了。

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

然后可以将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 magic,同样在托管Dao中。您可以通过错误处理等使其更加健壮来改进它

即使您使用的是示例中所示的托管资源,这种方法也有效。发生的情况是DropWizards RequestDispatcher激活并执行与您相同的操作:它打开一个会话并将其绑定到线程。其效果是,托管资源使用的会话与您手动打开的会话不同,并且您最初绑定的会话将在不进行清理的情况下被删除。在您的示例中,这样做的效果是,在调用doFilter(…)之后,魔术结束了。如果以后要访问数据库,必须重新绑定之前创建的会话。只要打电话:

        ManagedSessionContext.bind(session);

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

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

但是,要使这项工作适用于Jersey资源以外的类,您需要使用

首先创建一个工厂

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

谢谢你的回答,但这不是正确的答案,我应该添加一个url模式。使用此解决方案将无法访问筛选器。访问令牌检查时也会出现错误:org.hibernate.HibernateException:当前没有绑定到执行上下文的会话如何以这种方式添加url模式?我不确定是否正确,但是,您不能从containerRequest对象获取url并执行以下操作:final Pattern urlPattern=Pattern.compile(“url regex Pattern”);如果(urlPattern.matcher(containerRequest.getAbsolutePath().getPath()).matches(){return containerRequest;}我不使用Hibernate,所以我确定是什么导致了这个问题。检查用户名和密码是否有效。:)是否只有在使用过滤器时您才有Hibernate问题?如果没有,请尝试隔离问题。我在创建dropwizard任务时也使用了此方法来解决相同的问题。