【发布时间】:2019-09-05 15:42:32
【问题描述】:
Spring 不想使用我的 PrincipalExtractor bean。相反,它使用默认的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 并不想使用我的PrincipalExtractor bean,而是使用默认的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 (Why is my spring @bean never instantiated?)
没有任何变化。
- 添加 ResourceServerTokenServices (PrincipalExtractor and AuthoritiesExtractor doesn't hit)
Spring 找不到 UserInfoRestTemplateFactory。我猜手动添加 bean 是不对的,而且根本行不通。
- 许多不同的解决方案。他们都没有工作。
【问题讨论】:
-
面临同样的问题...
标签: java spring spring-boot spring-security spring-security-oauth2