Итак, я следовал руководству здесь для реализации Spring Authorization Server.Мне удалось подготовить клиент и сервер к тестированию.Причина, по которой мне нужен сервер авторизации, заключается в том, что мне нужно иметь возможность аутентифицировать несколько микросервисов, которые работают вместе.
Я запустил сервер и клиент на своем компьютере.Сервер авторизации на localhost:9999
и клиент на localhost:8080/client
(установка пути контекста клиентского приложения в / client).Аутентификация для клиента отлично работает в этом сценарии.Чтобы сделать это проще, я решил разместить сервер авторизации в AWS, используя Elastic Beanstalk.Для обеспечения секретности я буду использовать SERVER_URL в качестве URL-адреса размещенного сервера авторизации.
После размещения сервера я запускаю клиент с помощью размещенного сервера авторизации с правильными токенами и URL-адресами авторизации.Как только я перехожу на localhost:8080
, меня перенаправляют на SERVER_URL, где на главной странице отображается ссылка для входа в Google OAuth.При нажатии на эту ссылку я перехожу на страницу входа в Google, и я захожу в свою учетную запись Google.После входа в Google он перенаправляет обратно на SERVER_URL/login?code=the_code&state=the_state
.Это не то, что я хочу.После входа в Google пользователь должен быть перенаправлен обратно на localhost:8080/login?code=the_code&state=the_state
.
Я исследовал несколько дней, но, похоже, не могу найти решение этой проблемы.Мне нужно иметь возможность тестировать несколько микросервисов на локальном хосте с размещенным сервером.
Класс основного приложения моего сервера авторизации по умолчанию (я ничего не добавил).Вот моя конфигурация безопасности:
@Configuration
@EnableWebSecurity
@EnableOAuth2Client
@EnableAuthorizationServer
@Order(200)
public class OAuthSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final String GOOGLE_LOGIN_FILTER = "/login/google";
@Autowired
OAuth2ClientContext oauth2ClientContext;
@Bean
@ConfigurationProperties("google")
public ClientResources google() {
return new ClientResources();
}
private Filter ssoFilter() {
return ssoFilter(google(), GOOGLE_LOGIN_FILTER);
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter googleFilter = new OAuth2ClientAuthenticationProcessingFilter(GOOGLE_LOGIN_FILTER);
OAuth2RestTemplate googleTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
googleFilter.setRestTemplate(googleTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(), client.getClient().getClientId());
tokenServices.setRestTemplate(googleTemplate);
googleFilter.setTokenServices(tokenServices);
return googleFilter;
}
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<OAuth2ClientContextFilter>();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
/**
* Specify the authorization criteria for request access.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
.and()
.logout()
.logoutSuccessUrl("/")
.permitAll()
.and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
.csrf()
.disable();
}
}
class ClientResources {
@NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
@NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();
public AuthorizationCodeResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
Тогда у меня есть отдельный класс для защиты пути "/ me":
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/me")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
И мой application.yml
для сервера аутентификации:
spring:
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
server:
port: ${PORT:9999}
error:
whitelabel:
enabled: false
security:
oauth2:
client:
client-id: google client id
client-secret: google client secret
scope: read,write
auto-approve-scopes: '.*'
google:
client:
clientId: google client id
clientSecret: google client secret
accessTokenUri: https://oauth2.googleapis.com/token
userAuthorizationUri: https://accounts.google.com/o/oauth2/auth
clientAuthenticationScheme: form
scope:
- openid
- profile
- email
resource:
userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
preferTokenInfo: true
Контроллер для пути "/ me" тривиален, поэтому я не буду его здесь включать.И да, я использую один и тот же идентификатор клиента Google и секретный ключ для Google и самого сервера (пока).
Теперь на стороне моего клиента application.yml
:
authorization-server-url: SERVER_URL
security:
oauth2:
client:
clientId: google client id
clientSecret: google client secret
accessTokenUri: ${authorization-server-url}/oauth/token
userAuthorizationUri: ${authorization-server-url}/oauth/authorize
resource:
userInfoUri: ${authorization-server-url}/me
И конфигурация безопасности на моей стороне клиента использует @Configurable, @EnableWebSecurity и @ EnableOAuth2SSO.Конфигурация безопасности предотвращает доступ неаутентифицированных пользователей, поэтому, как только я захожу на localhost: 8080, он перенаправляет меня на сервер аутентификации.
Сервер аутентификации, когда он используется сам по себе, успешно входит в Google.И если клиентское приложение на localhost: 8080 настроено для проверки подлинности с помощью Google OAuth напрямую, а не на настраиваемом сервере аутентификации, то это выполняется успешно.Проблема заключается в правильном перенаправлении после того, как сервер авторизации вошел в систему с Google.
Просто чтобы уточнить, я после потока localhost:8080
-> сервер аутентификации -> нажмите ссылку, которая приведет вас к SERVER_URL/login/google
-> Войти через Google -> localhost:8080
.Но я получаю localhost:8080
-> сервер авторизации -> ссылку для перехода на SERVER_URL/login/google
-> Войти через Google -> SERVER_URL/login?code=the_code&state=the_s
tate.
Заранее спасибо.
РЕДАКТИРОВАТЬ:
Вот моя конфигурация gradle:
buildscript {
ext {
springBootVersion = '2.0.5.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse-wtp'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'war'
group = this is a secret
version = '0.0.4-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
providedRuntime
}
ext {
springCloudVersion = 'Finchley.SR1'
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-security')
implementation('org.springframework.boot:spring-boot-starter-web')
implementation('org.springframework.cloud:spring-cloud-starter-oauth2')
implementation('javax.servlet:jstl')
implementation('org.apache.tomcat.embed:tomcat-embed-jasper')
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
testImplementation('org.springframework.boot:spring-boot-starter-test')
testImplementation('org.springframework.security:spring-security-test')
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
РЕДАКТИРОВАТЬ 2:
Страница ошибкиЯ получаю по адресу http://<SERVER_URL>/login?code=xgYiHr&state=Wp1SUW
, где <SERVER_URL>
- доменное имя сервера авторизации.И я получаю следующую страницу ошибки:
И сетевой трафик для страницы ошибки.В соответствии с этим, http://<SERVER_URL>/oauth/authorize
имеет правильный redirect_uri
, который равен http://localhost:8080/login
, но когда дело доходит до перенаправления на него, URL localhost:8080
заменяется на <SERVER_URL>
:
Забавно, я только что попробовал запустить клиентское приложение через http://127.0.0.1:8080
вместо http://localhost:8080
, и оно отлично работает!Не уверен, почему localhost:8080
заменяется на <SERVER_URL>
.Я не уверен, что это проблема с AWS или Spring.