Spring не хочет использовать мой PrincipalExtractor
боб. Вместо этого он использует значение по умолчанию FixedPrincipalExtractor
.
Я пытаюсь следовать руководству Spring для OAuth2:
https://spring.io/guides/tutorials/spring-boot-oauth2/
И все прошло почти нормально, пока я не решил сохранить аутентифицированного пользователя в моей базе данных. В учебнике просто говорится: «Это слишком просто, поэтому мы не будем показывать, как это сделать». Конечно, это момент, когда я застрял на несколько дней.
Есть WebSecurityConfig
класс. Это беспорядок, но он используется в образовательных целях.
@Configuration
@EnableWebSecurity
@EnableOAuth2Client
@RestController
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
OAuth2ClientContext oauth2ClientContext;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**", "/js/**", "/error**", "/webjars/**").permitAll()
.anyRequest().authenticated()
.and().logout().logoutSuccessUrl("/").permitAll()
.and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(google(), "/login/google"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(oAuth2RestTemplate);
oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
return oAuth2ClientAuthenticationFilter;
}
@Bean
@ConfigurationProperties("google")
public ClientResources google() {
return new ClientResources();
}
@Bean
public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<OAuth2ClientContextFilter>();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
@Bean
public PrincipalExtractor principalExtractor(UserDetailsRepo userDetailsRepo) {
return map -> {
String id = (String) map.get("sub");
User user = userDetailsRepo.findById(id).orElseGet(() -> {
User newUser = new User();
newUser.setId(id);
newUser.setEmail((String) map.get("email"));
// and so on...
return newUser;
});
return userDetailsRepo.save(user);
};
}
}
class ClientResources {
@NestedConfigurationProperty
private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
@NestedConfigurationProperty
private ResourceServerProperties resource = new ResourceServerProperties();
public AuthorizationCodeResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
И application.yml
:
spring:
datasource:
url: jdbc:postgresql://localhost/my_db
username: postgres
password: password
jpa:
generate-ddl: true
properties:
hibernate:
jdbc:
lob:
non_contextual_creation: true
google:
client:
clientId: 437986124027-7072jmbsba04d11fft0h9megkqcpem2t.apps.googleusercontent.com
clientSecret: ${clientSecret}
accessTokenUri: https://www.googleapis.com/oauth2/v4/token
userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth
clientAuthenticationScheme: form
scope: openid,email,profile
resource:
userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
preferTokenInfo: true
Как я писал выше, Spring на самом деле не хочет использовать мой bean-компонент PrincipalExtractor
и вместо него использует стандартный FixedPrincipalExtractor
. Я потратил много времени, пытаясь решить эту проблему, но ничего не помогает. За исключением изменения application.yml
, например:
security:
oauth2:
client:
clientId: 620652621050-v6a9uqrjq0ejspm5oqbek48sl6od55gt.apps.googleusercontent.com
clientSecret: ${clientSecret}
[...]
resource:
userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
preferTokenInfo: true
Было google.client.clientId
и оно меняется на security.oauth2.client.clientId
, как вы можете видеть.
И если вы удалите все методы фильтра и все, что с ними связано, то это сработает, да. Это действительно использует мой PrincipleExtractor
. Но как я могу добавить больше провайдеров аутентификации (Facebook, GitHub и т. Д.) И локальной аутентификации сейчас?
Наконец, у меня есть несколько вопросов:
- Как заставить Spring использовать мой
PrincipalExtractor
?
- Должен ли я вообще использовать
PrincipalExtractor
? Может быть, есть другой способ сделать то же самое?
- Что-то не так с моим
application.yml
?
То, что я пробовал:
- Добавление сервера @EnableAuthorizationServer ( Почему мой источник @bean никогда не создается? )
Ничего не меняется.
- Добавление ResourceServerTokenServices ( ОсновныеExtractor и AuthoritiesExtractor не попадают )
Spring не может найти UserInfoRestTemplateFactory. Я полагаю, что добавлять бин вручную неправильно, просто не работает.
- Много разных решений. Никто из них не работал.