使用第三方身份验证保护资源服务器 RESTful API
Secure a resource server RESTful API with third party authentication
首先,我有一个使用 Spring Boot 开发的 oauth2 授权服务器,使用 @EnableAuthorizationServer 注释并扩展了 AuthorizationServerConfigurerAdapter。同样,有一个资源服务器用 @EnableResourceServer 注释扩展了 ResourceServerConfigurerAdapter。
场景:Android 具有 Google 登录名的应用程序必须以安全的方式调用我的后端 REST API 资源服务器。 Android 应用程序必须调用 REST API 来获取记录的用户信息,以使用我的授权服务器生成的提供的访问令牌来填充应用程序界面。尝试将应用程序与资源和授权服务器以及 Google 登录集成后,我发现了以下 Google 开发人员页面:https://developers.google.com/identity/sign-in/web/backend-auth
他们说:
If you use Google Sign-In with an app or site that communicates with a
backend server, you might need to identify the currently signed-in
user on the server. To do so securely, after a user successfully signs
in, send the user's ID token to your server using HTTPS. Then, on the
server, verify the integrity of the ID token and use the user
information contained in the token to establish a session or create a
new account.
好的,我可以添加一个端点来接收 ID 令牌,没问题。
其他会话,在同一页的末尾还说:
After you have verified the token, check if the user is already in
your user database. If so, establish an authenticated session for the
user. If the user isn't yet in your user database, create a new user
record from the information in the ID token payload, and establish a
session for the user. You can prompt the user for any additional
profile information you require when you detect a newly created user
in your app.
重点来了。在用户使用 Google 登录期间验证 Android 应用程序发送的 ID 令牌后,我如何将应用程序与 API 集成并在我的 Spring 上生成访问和刷新令牌授权服务器将它们发送到移动应用程序?
找到解决方案:我创建了自定义授权类型。这样我就可以覆盖身份验证以使用提供程序检查 ID 令牌(在这种情况下,Google),如果没问题,让正常流程完成它的工作。
我的实施基于:
这是我在 Kotlin 中的自定义实现:
1) 从 AuthorizationServerConfigurerAdapter
覆盖 configure(endpoints: AuthorizationServerEndpointsConfigurer)
:
override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
endpoints
.tokenStore(tokenStore)
.reuseRefreshTokens(false)
.accessTokenConverter(accessTokenConverter)
.authenticationManager(authenticationManager)
.userDetailsService(authUserDetails)
.tokenGranter(tokenGranter(endpoints))
}
private fun tokenGranter(endpoints: AuthorizationServerEndpointsConfigurer) =
CompositeTokenGranter(mutableListOf(endpoints.tokenGranter).apply {
add(GoogleTokenGranter(
tokenServices = endpoints.tokenServices,
clientDetailsService = endpoints.clientDetailsService,
requestFactory = endpoints.oAuth2RequestFactory,
grantType = GoogleTokenGranter.GRANT_TYPE
)
)
})
2) 自定义令牌授予者实施:
class GoogleTokenGranter internal constructor(
tokenServices: AuthorizationServerTokenServices,
clientDetailsService: ClientDetailsService,
requestFactory: OAuth2RequestFactory,
grantType: String
) : AbstractTokenGranter(tokenServices, clientDetailsService, requestFactory, grantType) {
override fun getOAuth2Authentication(client: ClientDetails, tokenRequest: TokenRequest): OAuth2Authentication {
// check token with google here
return super.getOAuth2Authentication(client, tokenRequest)
}
companion object {
const val GRANT_TYPE = "google"
}
}
客户端移动应用必须以这种方式发送请求:
POST /oauth/token
有效负载:
{
"grant_type": "google"
"username": "admin"
"token": "xxxxxxxxxxxxxxxxxxxxx"
}
不要忘记将授权 header 与您的客户端凭据一起发送,以 Spring 验证允许的大类型、范围等
首先,我有一个使用 Spring Boot 开发的 oauth2 授权服务器,使用 @EnableAuthorizationServer 注释并扩展了 AuthorizationServerConfigurerAdapter。同样,有一个资源服务器用 @EnableResourceServer 注释扩展了 ResourceServerConfigurerAdapter。
场景:Android 具有 Google 登录名的应用程序必须以安全的方式调用我的后端 REST API 资源服务器。 Android 应用程序必须调用 REST API 来获取记录的用户信息,以使用我的授权服务器生成的提供的访问令牌来填充应用程序界面。尝试将应用程序与资源和授权服务器以及 Google 登录集成后,我发现了以下 Google 开发人员页面:https://developers.google.com/identity/sign-in/web/backend-auth
他们说:
If you use Google Sign-In with an app or site that communicates with a backend server, you might need to identify the currently signed-in user on the server. To do so securely, after a user successfully signs in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity of the ID token and use the user information contained in the token to establish a session or create a new account.
好的,我可以添加一个端点来接收 ID 令牌,没问题。
其他会话,在同一页的末尾还说:
After you have verified the token, check if the user is already in your user database. If so, establish an authenticated session for the user. If the user isn't yet in your user database, create a new user record from the information in the ID token payload, and establish a session for the user. You can prompt the user for any additional profile information you require when you detect a newly created user in your app.
重点来了。在用户使用 Google 登录期间验证 Android 应用程序发送的 ID 令牌后,我如何将应用程序与 API 集成并在我的 Spring 上生成访问和刷新令牌授权服务器将它们发送到移动应用程序?
找到解决方案:我创建了自定义授权类型。这样我就可以覆盖身份验证以使用提供程序检查 ID 令牌(在这种情况下,Google),如果没问题,让正常流程完成它的工作。
我的实施基于:
这是我在 Kotlin 中的自定义实现:
1) 从 AuthorizationServerConfigurerAdapter
覆盖 configure(endpoints: AuthorizationServerEndpointsConfigurer)
:
override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) {
endpoints
.tokenStore(tokenStore)
.reuseRefreshTokens(false)
.accessTokenConverter(accessTokenConverter)
.authenticationManager(authenticationManager)
.userDetailsService(authUserDetails)
.tokenGranter(tokenGranter(endpoints))
}
private fun tokenGranter(endpoints: AuthorizationServerEndpointsConfigurer) =
CompositeTokenGranter(mutableListOf(endpoints.tokenGranter).apply {
add(GoogleTokenGranter(
tokenServices = endpoints.tokenServices,
clientDetailsService = endpoints.clientDetailsService,
requestFactory = endpoints.oAuth2RequestFactory,
grantType = GoogleTokenGranter.GRANT_TYPE
)
)
})
2) 自定义令牌授予者实施:
class GoogleTokenGranter internal constructor(
tokenServices: AuthorizationServerTokenServices,
clientDetailsService: ClientDetailsService,
requestFactory: OAuth2RequestFactory,
grantType: String
) : AbstractTokenGranter(tokenServices, clientDetailsService, requestFactory, grantType) {
override fun getOAuth2Authentication(client: ClientDetails, tokenRequest: TokenRequest): OAuth2Authentication {
// check token with google here
return super.getOAuth2Authentication(client, tokenRequest)
}
companion object {
const val GRANT_TYPE = "google"
}
}
客户端移动应用必须以这种方式发送请求:
POST /oauth/token
有效负载:
{
"grant_type": "google"
"username": "admin"
"token": "xxxxxxxxxxxxxxxxxxxxx"
}
不要忘记将授权 header 与您的客户端凭据一起发送,以 Spring 验证允许的大类型、范围等