Spring boot: внедрить пользовательский объект User с пользовательской инициализацией в запрос в контроллер - PullRequest
0 голосов
/ 20 февраля 2019

Я создаю приложение Spring Boot для предоставления REST API без сохранения состояния.В целях безопасности мы используем OAuth 2. Мое приложение получает токен только на предъявителя.

Информация о пользователе хранится в нашей базе данных.Я могу найти его, используя введенный принципал в контроллере:

@RequestMapping(...)
public void endpoint(Principal p) {
  MyUser user = this.myUserRepository.findById(p.getName());
  ...
}

Чтобы избежать этой дополнительной строки шаблона, я хотел бы иметь возможность внедрить объект MyUser непосредственно в метод моего контроллера.Как мне этого добиться?(Лучшее, что я придумала до сих пор, - это создать Ленивый @Bean в области Запросов ... но я не смог заставить его работать ...)

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Идиоматический путь

Идиоматический способ в Spring Security заключается в использовании UserDetailsService или реализации ваших собственных :

public class MyUserDetailsService implements UserDetailsService {
    @Autowired
    MyUserRepository myUserRepository;

    public UserDetails loadUserByUsername(String username) {
        return this.myUserRepository.findById(username);
    }
}

Кроме того, в Spring Security DSL есть несколько мест, где их можно разместить в зависимости от ваших потребностей.

После интеграции с методом аутентификации, который вы используете (в данном случае OAuth 2.0), вы можетебыть в состоянии сделать:

public void endpoint(@AuthenticationPrincipal MyUser myuser) {

}

Быстрый, но менее гибкий способ

Как правило, это лучше делать во время аутентификации (когда выясняется Принципал), а не в методе.время разрешения (с использованием преобразователя аргументов), поскольку оно позволяет использовать его в большем количестве сценариев аутентификации.

Тем не менее, вы также можете использовать преобразователь аргументов @AuthenticationPrincipal с любым зарегистрированным компонентом, например

public void endpoint(
    @AuthenticationPrincipal(expression="@myBean.convert(#this)") MyUser user) 
{

}

...

@Bean
public Converter<Principal, MyUser> myBean() {
    return principal -> this.myUserRepository.findById(p.getName())
}

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

0 голосов
/ 20 февраля 2019

Этого можно добиться, реализовав HandlerMethodArgumentResolver.Например:

Пользовательская аннотация:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Version {
}

Реализация:

public class HeaderVersionArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter methodParameter) {
    return methodParameter.getParameterAnnotation(Version.class) != null;
}

@Override
public Object resolveArgument(
  MethodParameter methodParameter, 
  ModelAndViewContainer modelAndViewContainer, 
  NativeWebRequest nativeWebRequest, 
  WebDataBinderFactory webDataBinderFactory) throws Exception {

    HttpServletRequest request 
      = (HttpServletRequest) nativeWebRequest.getNativeRequest();

    return request.getHeader("Version");
}
}

Когда вы реализуете это, вы должны добавить это как решатель аргументов:

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addArgumentResolvers(
  List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new HeaderVersionArgumentResolver());
}
}

Теперь мы можем использовать его в качестве аргумента

public ResponseEntity findByVersion(@PathVariable Long id, @Version String version) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...