2017-02-22 53 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)); 
} 

Теперь, как вы можете видеть здесь, я передаю мой Пользователь дао в моем идентифицирующей ... нет учебник я видел в Интернете делает это, и это потому, что каждые учебник онлайн использования жестко закодированные значения вместо того, чтобы показывать, как запросить БД.

Это говорит, вот как я пытаюсь проверить подлинность ...

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 

Вот кикер, я знаю, что это только для аспекта безопасности этого, что я получаю эту ошибку, потому что если я удалить линии безопасности из класса Application и запустите его, я все равно могу я создаю конечные точки пользователя (которые также используют этот DAO), и это работает хорошо.

Так что мой вопрос здесь действительно, есть - Я хотел использовать это дао в аутентификаторе? Если нет, как, черт возьми, я хочу запросить базу данных?

Если я, то где я иду не так?

Заранее спасибо.

+0

Не слишком много времени прямо сейчас, но я считаю, что вам нужно смотреть на «Единица работы» аннотации к DW.Они соединяют контекст jersey с гибернацией – pandaadb

+0

Мой ресурс, который вызывает это, использует @UnitOfWork уже - вот почему я смущен этим. – MickeyThreeSheds

+1

Я не вижу никакого brdiging. Просто аннотировать метод ресурса будет недостаточно, если трикотаж не знает о ваших DAO. Вы должны прочитать последний раздел на http://www.dropwizard.io/1.0.6/docs/manual/hibernate.html#transactional-resource-methods-outside-jersey-resources, который рассказывает вам, как перевести hibernate в джерси экосистема. Ключевое слово: UnitOfWorkAwareProxyFactory – pandaadb

ответ

2

Во-первых, ваш вопрос:

Из документации DW:

В настоящее время создание сделок с @UnitOfWork аннотацию работы вне коробки только для ресурсов, управляемых Джерси. Если вы хотите использовать его за пределами ресурсов Джерси, например. в аутентификаторах вы должны создать экземпляр класса с помощью UnitOfWorkAwareProxyFactory.

С кодом, вы создаете Authenticator, но вы никогда не подключаете его к сеансу спящего режима. Как бы знать, когда нужно открыть новый сеанс для DAO? Это делается с помощью механизма UnitOfWork. Это, однако, только в настоящее время работает для ресурсов Джерси и должно быть включено для любого другого класса, который хочет участвовать в этом.

Так, к счастью Docs дает нам точный 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(); 
     } 
    } 

} 

В приведенном выше коде используется минимальное приложение DW с настройкой h2 db в памяти.Вам придется применить изменения конфигурации так, что она начинается (и изменить файл конфигурации сервера)

Что это делает:

  1. Создать сверток спящий режим, снабжающих DataSourceFactory
  2. Создание DAO
  3. Создание Authenticator как прокси-сервер
  4. Wire все это вместе

важные биты:

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 DI с Spring DI таким образом, что jersey может получить доступ к этим компонентам в Spring. Однако вся логика session по-прежнему обрабатывается одинаково. Spring просто берет явную абстракцию от afaik - он создает прокси для вас уже при создании компонента. Поэтому я не думаю, что у вас будет много преимуществ с этим и из личного опыта, но не так легко справиться с весной и Джерси. Зависимость (spring-jersey-bridge) jersey advertises не работает со встроенными Jetty (например, настройками DW), а, например, путем подключения к сервлету при запуске (которого у вас нет). Это может по-прежнему работать, однако для этого требуется немного взлома. По моему опыту, guice (например, https://github.com/xvik/dropwizard-guicey) объединяет намного проще и приятнее в DW и даст вам те же преимущества. Guice, очевидно, не делает все, что делает Весна (ни Spring не делает все, что делает Guice), поэтому вам, возможно, придется провести собственное исследование.

Я надеюсь, что это очищает вещи и получает вы начали :)

С уважением,

Артуру