2017-02-22 67 views
3

我想我有一個公平的想法我的問題是什麼在這裏,但也絕對不知道我怎麼可能解決它會...Dropwizard和Hibernate - 沒有當前綁定到執行上下文

這是我如何我開始我在dropwizard應用:

@Override 
public void run(ServerConfiguration configuration, Environment environment) 
{ 

    // Setting up the database. 
    final DBIFactory factory = new DBIFactory(); 
    final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "mysql"); 

    //Hibernate 
    final UserDAO dao = new UserDAO(hibernate.getSessionFactory()); 
    environment.jersey().register(new UserResource(dao)); 

    final TemplateHealthCheck healthCheck = new TemplateHealthCheck(configuration.getTemplate()); 

    environment.healthChecks().register("template", healthCheck); 

    // security 
    //****** Dropwizard security - custom classes ***********/ 
    environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>() 
      .setAuthenticator(new BasicAuth(dao)) 
      .setAuthorizer(new BasicAuthorizer()) 
      .setRealm("BASIC-AUTH-REALM") 
      .buildAuthFilter())); 
    environment.jersey().register(RolesAllowedDynamicFeature.class); 
    environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class)); 
} 

現在,你可以看到這裏,我通過我的用戶DAO到我的認證...... 沒有教程,我在網上做到這一點看出來了,這是因爲每一個在線教程用途硬編碼值而不是顯示如何查詢數據庫。

這就是說,這裏是我正在試圖驗證...

public class BasicAuth implements Authenticator<BasicCredentials, User> { 

UserDAO _userDAO; 
final Encryption enc = new Encryption(); 

public BasicAuth(UserDAO dao) 
{ 
    this._userDAO = dao; 
} 

@Override 
public Optional<User> authenticate(BasicCredentials credentials) 
     throws AuthenticationException { 

    // Get the user record. 
    User requestedUser = _userDAO.findOneByUsername(credentials.getUsername()); 

    if (requestedUser != null) 
    { 
     // check pw. 
     if(enc.compare(credentials.getPassword(), requestedUser.getPassword())) { 
      return Optional.of(requestedUser); 
     } 
     else { 
      return Optional.empty(); 
     } 
    } 
    return Optional.empty(); 
} 
} 

請原諒以上可怕的缺口,我貼我的代碼從這裏的IntelliJ和它只是不表現很好 - 反正,當我嘗試運行此應用程序中,驗證告訴我:

No session currently bound to execution context 

這裏是踢球的,我知道這僅僅是本作的安全方面,我得到這個錯誤,因爲如果我刪除了安全線從應用程序類,並運行它,我仍然可以打我的創建用戶端點(也使用此DAO),並且運行良好。

所以我在這裏的問題真的是 - 我是否打算在驗證器中使用該dao?如果不是,我該怎麼查詢數據庫?

如果我是,那麼我會錯在哪裏?

在此先感謝。

+0

沒有太多的時間,現在,但我相信你需要尋找到「工作單位」 DW上的註釋。他們將球衣上下文連接到休眠 – pandaadb

+0

我的資源調用了這個已經使用@UnitOfWork - 這就是爲什麼我對此感到困惑。 – MickeyThreeSheds

+1

雖然我看不到任何brdiging。如果球衣不知道你的DAO,只註釋資源方法是不夠的。你需要閱讀http://www.dropwizard.io/1.0.6/docs/manual/hibernate.html#transactional-resource-methods-outside-jersey-resources上的最後一節,它告訴你如何讓休眠進入球衣生態系統。關鍵字:UnitOfWorkAwareProxyFactory – pandaadb

回答

2

首先,您的問題:

從DW文檔:

與@UnitOfWork註釋目前創建工作事務外的盒子只能由新澤西州管理的資源 。如果您想在Jersey資源外使用它 ,例如在身份驗證器中,您應該使用UnitOfWorkAwareProxyFactory實例化您的類。

通過您的代碼,您可以創建一個Authenticator,但您永遠不會將其掛回到Hibernate會話。 Authenticator如何知道何時開啓DAO的新會話以進行操作?這由UnitOfWork機制完成。然而,目前這隻適用於澤西島的資源,並且需要爲任何其他希望參與其中的課程啓用。

所以,幸運的是Google文檔提供了我們這裏的確切Authenticator例如: http://www.dropwizard.io/1.0.6/docs/manual/hibernate.html

我不會去複製他們的代碼,因爲我有一個獨立的例子讓你玩:

public class HibernateTest extends io.dropwizard.Application<DBConfiguration> { 

    private final HibernateBundle<DBConfiguration> hibernate = new HibernateBundle<DBConfiguration>(Object.class) { 
     @Override 
     public DataSourceFactory getDataSourceFactory(DBConfiguration configuration) { 
      return configuration.getDataSourceFactory(); 
     } 
    }; 

    @Override 
    public void initialize(Bootstrap<DBConfiguration> bootstrap) { 
     super.initialize(bootstrap); 
     bootstrap.addBundle(hibernate); 
    } 

    @Override 
    public void run(DBConfiguration configuration, Environment environment) throws Exception { 
     MyDao dao = new MyDao(hibernate.getSessionFactory()); 
     environment.jersey().register(new MyHelloResource(dao)); 


     // THIS IS ABSOLUTELY CRITICAL 
     MyAuthenticator proxyAuth = new UnitOfWorkAwareProxyFactory(hibernate).create(MyAuthenticator.class, MyDao.class, dao); 

     AuthDynamicFeature authDynamicFeature = new AuthDynamicFeature(
       new BasicCredentialAuthFilter.Builder<Principal>() 
        .setAuthenticator(proxyAuth) 
        .setRealm("SUPER SECRET STUFF") 
        .buildAuthFilter()); 

     environment.jersey().register(authDynamicFeature); 
    } 

    public static void main(String[] args) throws Exception { 
     new HibernateTest().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/db.yaml"); 
    } 

    @Path("test") 
    @Produces(MediaType.APPLICATION_JSON) 
    public static class MyHelloResource { 

     private MyDao dao; 

     public MyHelloResource(MyDao dao) { 
      this.dao = dao; 
     } 

     @GET 
     @Path("/test") 
     @UnitOfWork 
     @PermitAll 
     public Response downloadFile() throws Exception { 
      dao.get(); 
      return Response.ok().build(); 
     } 

    } 

    public static class MyAuthenticator implements Authenticator<BasicCredentials, Principal> { 
     private MyDao dao; 

     MyAuthenticator(MyDao dao) { 
      this.dao = dao; 
     } 

     @Override 
     @UnitOfWork 
     public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException { 
      dao.get(); 
      return Optional.empty(); 
     } 
    } 

    public static class MyDao extends AbstractDAO<Object> { 

     public MyDao(SessionFactory sessionFactory) { 
      super(sessionFactory); 
     } 

     public Object get() { 
      // if not bridged to Jersey this will throw an exception due to session 
      currentSession().createSQLQuery("SELECT 1;").uniqueResult(); 
      return new Object(); 
     } 
    } 

} 

上面的代碼在內存中運行一個具有h2數據庫設置的最小DW應用程序。你將不得不申請您的配置更改,使其開始(和更改服務器的配置文件)

這樣做是:

  1. 創建休眠束供給的DataSourceFactory
  2. 創建DAO
  3. 作爲代理
  4. 線創建Authenticator所有的一起

重要的位是:

MyAuthenticator proxyAuth = new UnitOfWorkAwareProxyFactory(hibernate).create(MyAuthenticator.class, MyDao.class, dao); 

這將創建一個代理,你是知道的UnitOfWork註釋。它使Authenticator能夠掛鉤(我相信)事件系統,它可以根據請求打開和關閉會話。

您再使用該代理在AuthDynamicFeature

最後,在Authenticator你必須告訴它打開一個新的會話執行身份驗證時,如:

@Override 
     @UnitOfWork 
     public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException { 
      dao.get(); 
      return Optional.empty(); 
     } 

現在,所有的這將工作無異常:

curl user:[email protected]:9085/api/test/test 
Credentials are required to access this resource. 

至於你的最後一個問題:

我實際上比較流利的有春天,你認爲這會是一個不錯的想法,而不是不斷地處理這個問題嗎?

我認爲這主要是基於意見的,但是:Spring DI!= Jersey DI。你基本上和Spring做同樣的事情,你可以橋接Jersey DISpring DI,這樣jersey可以訪問Spring中的這些bean。但是,所有的session邏輯仍然以相同的方式處理。 Spring只需將顯式抽象afaik - 它在創建bean時已經爲您創建了代理。所以我認爲你不會有這方面的許多優勢,並且從個人經驗來看,將Spring和Jersey結合起來並不那麼容易。依賴關係(spring-jersey-bridge)球衣廣告不適用於嵌入式Jetty(如DW設置),而是在啓動時掛鉤到Servlet(您沒有)。這仍然可以工作,但它需要一些黑客來獲得該設置。根據我的經驗,guice(例如https://github.com/xvik/dropwizard-guicey)更容易和更好地融入數據倉庫,並且會給你相同的優勢。 Guice顯然不會做春天所做的所有事情(Spring也沒有做所有Guice所做的事情),因此您可能需要自己做一些研究。

我希望這將清除的東西了,並讓你開始:)

問候,

阿圖爾

相關問題