1

Я слишком долго рылся в сообщениях и получал головокружение, поэтому я надеюсь, что один из гуру может помочь мне в этом.Контейнер управляемый auth, ручка в настоящее время зарегистрированный пользователь

Я использую аутентификацию, управляемую контейнером, и она работает хорошо. У меня есть мои настройки Realm для проверки подлинности, установите Защищенные URLs в web.xml, есть страницы входа в систему и т.д.

Но теперь я ударяя проблема ...

У меня есть объекты JPA для моей модели данных и некоторые из этих объектов «проверяются» в том, что они отслеживают, когда они были созданы или обновлены, и , кто.

Я использую @PrePersist обработчик в моем коде, чтобы установить createdOn и updatedOn поля на упорствовать/обновление соответственно, например, так:

@PrePersist 
protected void onCreate() { 
    this.setCreatedOn(new Date()); 
} 

Это прекрасно работает, но мне не хватает, как я должен получить доступ для пользователя, который в настоящее время вошёл в систему отсюда ... Мне нужно это, чтобы установить поле createdBy.

Я использую Resteasy и в моей конечной точке у меня есть доступ к вошедшему пользователю, и я смог получить свой объект Account:

@Path("/test") 
public class TestEndpoint { 
    @EJB 
    AuthorizationService authService; 

    @GET 
    @Path("path") 
    @Produces("application/json") 
    @RolesAllowed("User") 
    public Response test() { 
     Account account = authService.getLoggedInAccount(); 
     return account == null ? Response.status(Status.NOT_FOUND).build() : Response.ok().entity(account).build(); 
    } 
} 

AuthorizationService это мой и выглядит следующим образом:

@Stateless 
@LocalBean 
public class AuthorizationService { 
    @Inject 
    HttpServletRequest request; 

    public Account getLoggedInAccount() { 
     Account result = (Account) request.getAttribute(LOGGED_IN_USER); 
     if (result == null) { 
      Principal principal = request.getUserPrincipal(); 
      if (principal != null) { 
       List<Account> results = crudService.find(Account.BY_NAME, Params.of("name", principal.getName()), 0, 0); 
       if (results != null && results.size() > 0) { 
        result = results.get(0); 
        request.setAttribute(LOGGED_IN_USER, result); 
       } 
      } 
     } 
     return result; 
    } 
} 

Это работает. Обратите внимание, что я кэширую зарегистрированного пользователя в атрибуте запроса, поэтому я не отправляю запрос в базу данных каждый раз.

До сих пор я был в состоянии получить с этой установкой, но я чувствую, что я делаю это все неправильно ...

Я хотел бы иметь одну глобальную точку перехвата (фильтр?), Где я заселить. ..something ... (запрос?) с текущим именем пользователя учетной записи пользователя, а затем иметь возможность вводить его там, где это необходимо ... Я бы очень хотел, чтобы решения, которые не создают сеанс, поскольку я пытаюсь сделать приложение как можно более масштабируемое.

Любые советы о том, как справиться с этим? Эта золотая ссылка на учебник, который объясняет это хорошо, может быть? Спасибо за помощь!

ответ

0

Существует набор predefined beans in CDI applications. Среди них java.security.Principal представляет собой идентификатор текущего вызывающего абонента. Таким образом, вам просто нужно @Inject Principal, где вам это нужно. Еще одна вещь, которую вы могли бы рассмотреть для своих конкретных потребностей, - это Auditing feature проекта модуля данных дельта-шипа, который может помочь вам сократить пользовательский код еще больше.

+0

Спасибо. это звучит как шаг вперед. Интересно, однако, если бы я мог сделать свой собственный класс Аккаунта доступным для инъекций? Было бы более удобно, чем использовать Принципала, чтобы получить его каждый раз. –

+0

В приведенной ссылке есть фрагмент кода, который иллюстрирует инъекцию пользователя: '@Inject private User user;'. Однако как сделать доступным для входа в систему пользователя для инъекций? –

+0

Контейнер несет ответственность за установку текущего пользователя в «Принципал». Поэтому, когда вы объявляете '@Inject Principal' в безопасном контексте JEE, основной экземпляр сопоставляется с текущим пользователем. Для особенностей дельта-шипа вы можете сделать что-то вроде: '@Inject private Principal Princip; @Produces @CurrentUser public String currentUser() { return main! = Null? Princip.getName(): "anonymous"; } ' – Franck

1

Ваш вопрос немного неясно, но я полагаю, из комментариев, которые вы хотите, чтобы иметь возможность вводить счет текущего вошедшего пользователя в ваших CDI бобов, как это:

@Inject @CurrentUser Account account; 

Для этого вам необходимо: - производитель CDI для настройки создания объекта учетной записи - вставьте принципал в производителя, чтобы вы могли найти подходящую учетную запись для зарегистрированного пользователя - Пользовательский @CurrentUser квалификатор для соответствия вашим точкам впрыска с производителем - производителю следует создать область действия с запросом bean - следовательно, вызов производителю (а затем в DB) кэшируется и exe вырезан только первый раз за запрос

Теперь пример кода производителя:

public class CurrentAccountProducer { 

    @Inject private Principal principal; // get logged-in principal 

    /* called first time per request to find Account entity for principal 
     - it will be cached and injected into @CurrentAccount @Inject points 
    */ 
    @CurrentAccount 
    @RequestScoped 
    @Produces 
    public Account produceAccount() { 
     if (principal == null) { 
      return null; // null will be injected if user is not logged in 
     } else { 
      // part of your original code here... 
      List<Account> results = crudService.find(Account.BY_NAME, Params.of("name", principal.getName()), 0, 0); 
       if (results != null && results.size() > 0) { 
        return results.get(0); 
       } 
     } 
    } 
} 

Этот производитель является все, что вам нужно, чтобы ввести счет для вошедшего в систему пользователя или нуль для анонимной. Затем вы можете изменить ваш AuthorizationService так:

@Stateless @LocalBean общественного класса AuthorizationService { @Inject @CurrentAccount счета currentAccount;

public Account getLoggedInAccount() { 
    return currentAccount; 
} 

}

Это может быть даже так легко, как инъекционные счет непосредственно в TestEndpoint, минуя AuthorizationService, но лучше инкапсулировать бизнес-логику в EJB для запуска логики в транзакции.

+0

«Ваш вопрос немного неясен» .. * идет с фантастическим ответом точно, чего я хочу достичь * ... :) Спасибо, спасибо! Я знаю, что мой вопрос был неясным, но я изучил EJB из практики, и даже после многих лет мне все еще трудно обсуждать это с другими ... Терминология так запутанна. Плюс он менялся так много раз, и все версии документов все еще в сети. Но, по сути, ваш ответ выглядит так, как будто это даст мне именно то, что я хочу. Идти, чтобы попробовать это, как только я найду время. –

+0

@OndrejM В методе productAccount отсутствует аннотация '@ Produces'. Возможно, вы захотите обновить свой ответ. – Franck

+0

@ Франк, ты прав. Я обновил свой ответ. Благодаря! – OndrejM