В предыдущем посте я рассказал о том, как вызвать сервер авторизации OAuth2 с помощью UAA- проекта Cloud Foundry и заполнить его некоторыми участниками процесса авторизации OAuth2.
Я обнаружил, что эта статья на сайте Digital Ocean отлично справляется с описанием потока кода авторизации OAuth2, поэтому вместо того, чтобы перефразировать то, что задействовано в этом потоке, я непосредственно перейду к реализации этого потока с помощью Spring Boot / Spring Security.
На следующей диаграмме, вдохновленной приведенной здесь, показан поток высокого уровня в типе предоставления кода авторизации:
У меня будет два приложения — сервер ресурсов, представляющий некоторые ресурсы пользователя, и клиентское приложение, которое хочет получить доступ к этим ресурсам от имени пользователя. Сам сервер авторизации может быть запущен, как описано в предыдущем сообщении в блоге .
Остальная часть поста может быть легко прослежена вместе с кодом, доступным в моем репозитории github здесь
Сервер авторизации
Сервер Cloud Foundry UAA можно легко запустить с помощью шагов, описанных в моем предыдущем сообщении в блоге . После запуска следующие команды uaac можно использовать для ввода различных учетных данных, необходимых для запуска образца.
Эти сценарии создадут учетные данные клиента для клиентского приложения и добавят пользователя с именем «user1» с областью «resource.read» и «resource.write».
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# Login as a canned clientuaac token client get admin -s adminsecret# Add a client credential with client_id of client1 and client_secret of client1uaac client add client1 \ --name client1 \ --scope resource.read,resource.write \ -s client1 \ --authorized_grant_types authorization_code,refresh_token,client_credentials \ --authorities uaa.resource# Another client credential resource1/resource1uaac client add resource1 \ --name resource1 \ -s resource1 \ --authorized_grant_types client_credentials \ --authorities uaa.resource# Add a user called user1/user1uaac user add user1 -p user1 --emails user1@user1.com# Add two scopes resource.read, resource.writeuaac group add resource.readuaac group add resource.write# Assign user1 both resource.read, resource.write scopes..uaac member add resource.read user1uaac member add resource.write user1 |
Ресурсный сервер
Сервер ресурсов предоставляет несколько конечных точек, выраженных с помощью Spring MVC и защищенных с помощью Spring Security, следующим образом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@RestControllerpublic class GreetingsController { @PreAuthorize("#oauth2.hasScope('resource.read')") @RequestMapping(method = RequestMethod.GET, value = "/secured/read") @ResponseBody public String read(Authentication authentication) { return String.format("Read Called: Hello %s", authentication.getCredentials()); } @PreAuthorize("#oauth2.hasScope('resource.write')") @RequestMapping(method = RequestMethod.GET, value = "/secured/write") @ResponseBody public String write(Authentication authentication) { return String.format("Write Called: Hello %s", authentication.getCredentials()); }} |
Доступны две конечные точки uri — «/ secured / read», авторизованный для области «resource.read» и «/ secured / write», авторизованный для области «resource.write»
Конфигурация, которая защищает эти конечные точки и помечает приложение как сервер ресурсов, следующая:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Configuration@EnableResourceServer@EnableWebSecurity@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId("resource"); } @Override public void configure(HttpSecurity http) throws Exception { http .antMatcher("/secured/**") .authorizeRequests() .anyRequest().authenticated(); }} |
Эта конфигурация вместе со свойствами, описывающими способ проверки токена, — это все, что требуется для запуска сервера ресурсов.
клиент
Конфигурация клиента для OAuth2 с использованием Spring Security OAuth2 также довольно проста: аннотация @ EnableAuth2SSO включает всю необходимую конфигурацию для подключения пружинных фильтров безопасности для потоков OAuth2:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@EnableOAuth2Sso@Configurationpublic class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { super.configure(web); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); //@formatter:off http.authorizeRequests() .antMatchers("/secured/**") .authenticated() .antMatchers("/") .permitAll() .anyRequest() .authenticated(); //@formatter:on }} |
Чтобы вызвать нисходящую систему, клиент должен передать токен OAuth в качестве заголовка в нисходящих вызовах, это делается путем перехвата специализированного RestTemplate, называемого OAuth2RestTemplate, который может получить токен доступа из контекста и передать его в нисходящем направлении, как только он подключен безопасный нисходящий вызов выглядит так:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public class DownstreamServiceHandler { private final OAuth2RestTemplate oAuth2RestTemplate; private final String resourceUrl; public DownstreamServiceHandler(OAuth2RestTemplate oAuth2RestTemplate, String resourceUrl) { this.oAuth2RestTemplate = oAuth2RestTemplate; this.resourceUrl = resourceUrl; } public String callRead() { return callDownstream(String.format("%s/secured/read", resourceUrl)); } public String callWrite() { return callDownstream(String.format("%s/secured/write", resourceUrl)); } public String callInvalidScope() { return callDownstream(String.format("%s/secured/invalid", resourceUrl)); } private String callDownstream(String uri) { try { ResponseEntity<String> responseEntity = this.oAuth2RestTemplate.getForEntity(uri, String.class); return responseEntity.getBody(); } catch(HttpStatusCodeException statusCodeException) { return statusCodeException.getResponseBodyAsString(); } }} |
демонстрация
Клиент и сервер ресурсов могут быть запущены с использованием приведенных здесь инструкций. Как только все системы будут запущены, доступ к клиенту предоставит пользователю страницу, которая выглядит следующим образом:

Доступ к защищенной странице приведет к тому, что страница авторизации будет представлена сервером авторизации:
Клиент запрашивает у пользователя область «resource.read» и «resource.write», пользователю предлагается авторизовать следующие области:
Предполагая, что пользователь авторизовал «resource.read», но не «resource.write», токен будет представлен пользователю:

На этом этапе, если запрашивается нисходящий ресурс, который требует области действия «resource.read», он должен быть получен:
И если нисходящий ресурс запрашивается с областью, которую пользователь не авторизовал — «resource.write» в этом случае:
Ссылка
- Большая часть кода основана на образцах приложений Cloud Foundry UAA, доступных здесь — https://github.com/pivotal-cf/identity-sample-apps
- Код в посте находится здесь : https://github.com/bijukunjummen/oauth-uaa-sample
| Ссылка: | Использование сервера авторизации UAA OAuth2 — клиента и ресурса от нашего партнера по JCG Бижу Кунджуммена в блоге all and sundry. |




