我正在使用 Spring Security 6 实现一个 Spring 授权服务器。对本地数据库中注册的用户进行简单身份验证已经实现,并完美生成访问令牌。
我需要使用 Google 作为身份验证提供程序来实现社交登录,但我需要访问令牌继续由我的授权服务器生成,也就是说,Google 服务将仅负责登录以及当授权服务器收到肯定时来自 Google 的响应,将使用用户名在本地数据库中搜索权限和其他用户数据以生成令牌,然后将此令牌返回给客户端。
我找不到任何可以帮助我完成此任务的示例,因此我将非常感谢任何帮助。
注意:我已经配置了 Google 帐户,现在可以与授权服务器通信。
我的安全过滤器链配置
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(oidc -> oidc
.userInfoEndpoint(userInfo -> userInfo.userInfoMapper(userInfoMapper()))
.logoutEndpoint(withDefaults()));
http.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint(FORM_LOGIN_URL)))
.oauth2ResourceServer(resourceServer -> resourceServer.jwt(withDefaults()));
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain oauth2SecurityFilterChain(HttpSecurity http) throws Exception {
http
.oauth2ResourceServer(oauth2 -> oauth2.jwt(withDefaults()))
.formLogin(formLogin -> formLogin.loginPage(FORM_LOGIN_URL).permitAll())
.oauth2Login(oauth2 -> oauth2.loginPage(FORM_LOGIN_URL).permitAll())
.logout(logout -> logout
.logoutUrl(LOGOUT_ENDPOINT)
.logoutSuccessUrl(FORM_LOGIN_URL)
.deleteCookies("JSESSIONID", "remember-me")
.invalidateHttpSession(true)
.clearAuthentication(true));
return http.build();
}
配置授权服务器时,您需要为社交登录提供程序指定重定向 URI。根据 Spring Authz Server 文档,此重定向 URI 模板与此类似:
{baseUrl}/login/oauth2/code/{registrationId}
,其中 registrationId
是您在配置 authz 服务器时指定的社交客户端的唯一标识符。
当您的社交提供商完成身份验证后,它会将您重定向到此重定向 URI,其中包含经过身份验证的用户信息。您可以做的是,为此端点创建一个控制器并在此处处理您的用例。
例如: 您可以从以下位置检索身份验证:
var authentication = SecurityContextHolder.getContext().getAuthentication();
然后您可以检查此身份验证是否是
OAuth2AuthenticationToken
的实例,并从中获取 registrationId
和 principalName
。您可以使用这两个来调用 OAuth2AuthorizedClientService
并获取访问令牌。
var authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof OAuth2AuthenticationToken) {
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient authorizedClient = authorizedClientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName()
); // You can autowire OAuth2AuthorizedClientService
OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
return accessToken;
}
您可以参考此 GitHub 存储库 获取示例实现。 (免责声明:代码不是我写的)。也许还有其他方法可以使用
SecurityFilterChain
实现相同的效果,因此您可能也想探索这些方法。您还可以参考这篇Medium文章以获取更多参考。