2016-12-11 7 views
6

У меня есть два отдельных приложения Spring Boot, один из которых служит сервером авторизации OAuth 2, а другой - как сервер ресурсов. Я использую Spring RemoteTokenServices на моем сервере ресурсов для проверки токенов с сервера авторизации. Теперь я пытаюсь определить защищенный код контроллера в своем приложении сервера ресурсов, но я не уверен, как сопоставить класс UserDetails с принципалом аутентификации, предоставляемым через механизм OAuth 2.Как сопоставить токен OAuth 2 с объектом UserDetails на сервере ресурсов?

Я установил свой сервер авторизации с настраиваемым TokenEnhancer, который добавляет дополнительную информацию к токену, так что /oauth/check_token?token=<token> возвращает с настраиваемыми полями, которые я хочу сопоставить с контроллерами серверов ресурсов.

В более монолитной установке, где сервер авторизации является также ресурсы сервером, я могу определить методы контроллера, которые используют аутентифицированный принципал таким образом:

//User implements UserDetails 
public Map<String, Object> getResource(@AuthenticationPrincipal User user) { 
    //code that uses the user object 
} 

Однако, это не похоже на работу как прямо вперед в более распределенном подходе. Отображение не выполняется, и параметр user оказывается нулевым объектом. Я попытался с помощью следующего подхода:

public Map<String, Object> getResource(Authentication authentication) { 
    //code that uses the authentication object 
} 

Хотя приведенный выше код успешно отображает параметры аутентификации, он не обеспечивает способ для меня, чтобы получить прямой доступ к настраиваемых полей, которые я указал через TokenEnhancer я упоминал ранее. Кажется, я ничего не могу найти в документах Spring об этом.

ответ

8

Для решения проблемы позвольте мне сначала пройти немного архитектурного фона. Объект UserDetails, автоматически отображаемый через @AuthenticationPrincipal, исходит из поля principal активного объекта Authentication. Контроллер сервера ресурсов имеет доступ к объекту OAuth2Authencation, который является специализированным экземпляром Authentication для инфраструктуры безопасности Spring OAuth2, просто объявив его как часть параметров метода.

public void controllerMethod(OAuth2Authentication authentication) { 
    //controller definition 
} 

Зная это, теперь проблема смещается в том, чтобы убедиться, что метод getPrincipal() в Authentication объект является экземпляром моего пользовательского класса UserDetails. RemoteTokenServices Я использую в приложении сервера ресурсов экземпляр AccessTokenConverter для интерпретации данных маркера, отправленных сервером авторизации. По умолчанию он использует DefaultAccessTokenConverter, который просто устанавливает принципал аутентификации как имя пользователя, которое является String. Этот преобразователь использует UserAuthenticationConverter для преобразования данных, поступающих с сервера авторизации, в экземпляр Authentication. Это то, что мне нужно настроить:

DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter(); 
tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() { 

    @Override 
    public Authentication extractAuthentication(Map<String, ?> map) { 
     Authentication authentication = super.extractAuthentication(map); 
     // User is my custom UserDetails class 
     User user = new User(); 
     user.setSpecialKey(map.get("specialKey").toString()); 
     return new UsernamePasswordAuthenticationToken(user, 
       authentication.getCredentials(), authentication.getAuthorities()); 
    } 

}); 
tokenServices.setAccessTokenConverter(tokenConverter); 

Со всеми этими создали механизм @AuthenticationPrincipal теперь работает, как ожидалось.

+0

Это решение работает, но это скорее обходное решение, чем исправление. Причина, по которой вы получаете String for Princip, заключается в том, что userDetailsService неправильно введен в DefaultUserAuthenticationConverter(). Теперь вопрос заключается в том, где его нужно вводить, чтобы это обходное решение не требовалось? – zalis

0

Включите AuthenticationPrincipalArgumentResolver, как показано в xml?

<mvc:annotation-driven> 
     <mvc:argument-resolvers> 
       <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" /> 
     </mvc:argument-resolvers> 
</mvc:annotation-driven> 

И вы должны реализовать UserDetails вернуть свой собственный CustomerUser object, то вы можете использовать аннотацию, чтобы получить главный непосредственно.

+0

Мне никогда не приходилось определять это явно. Я думаю, что resolver уже является частью автоконфигурации Spring Boot. –

+0

@PsychoPunch Это так. – chrylis