如何让 Linkedin OAuth 在 Spring Boot 中工作
Posted
技术标签:
【中文标题】如何让 Linkedin OAuth 在 Spring Boot 中工作【英文标题】:How to get Linkedin OAuth working in Spring Boot 【发布时间】:2020-03-04 17:31:25 【问题描述】:在使用 Spring OAuth2 的 Spring boot 2.1.6.RELEASE
项目中拥有 Login with Linkedin
需要帮助。 Java版本是11
Google 和 Github 非常简单,并且在同一个项目中工作。我在 Spring-Social 中尝试了几个示例代码,但由于 Spring 引导版本不同,它们失败了。
下面的application.properties 不起作用(也试过client-authentication-method=post
),并在从linkedin 检索授权码后被重定向回来(授权码是有效的,我可以使用它从Postman 获取访问令牌)。
spring.security.oauth2.client.registration.linkedin.provider=linkedin
spring.security.oauth2.client.registration.linkedin.client-name=Linkedin
spring.security.oauth2.client.registration.linkedin.client-id=******
spring.security.oauth2.client.registration.linkedin.client-secret=******
spring.security.oauth2.client.registration.linkedin.redirect-uri=*****
spring.security.oauth2.client.registration.linkedin.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.linkedin.client-authentication-method=form
spring.security.oauth2.client.registration.linkedin.scope=r_emailaddress,r_liteprofile
spring.security.oauth2.client.provider.linkedin.authorization-uri=https://www.linkedin.com/oauth/v2/authorization
spring.security.oauth2.client.provider.linkedin.token-uri=https://www.linkedin.com/oauth/v2/accessToken
spring.security.oauth2.client.provider.linkedin.user-info-uri=https://api.linkedin.com/v2/me
spring.security.oauth2.client.provider.linkedin.user-info-authentication-method=post
SecurityConfig 类(也尝试不使用antMatchers
):
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http.authorizeRequests().antMatchers("*linkedin*").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.oauth2Login();
没有报错,code
查询参数与state
一起返回Spring后,重定向回Spring登录。
谢谢
【问题讨论】:
【参考方案1】:我的工作配置:
spring:
security:
oauth2:
client:
registration:
linkedin:
client-id: ????
client-secret: ????
scope: r_liteprofile, r_emailaddress
authorization-grant-type: authorization_code
redirect-uri: "baseUrl/login/oauth2/code/registrationId"
client-name: LinkedIn
client-authentication-method: post
provider:
linkedin:
authorization-uri: https://www.linkedin.com/oauth/v2/authorization
token-uri: https://www.linkedin.com/uas/oauth2/accessToken
user-info-uri: https://api.linkedin.com/v2/me
jwk-set-uri:
user-name-attribute: id
最近的春天:
org.springframework.security:spring-security-oauth2-client:5.2.2.RELEASE
【讨论】:
在我的情况下它不起作用,您能否分享一些它的源代码。谢谢 我被困在http://localhost:8080/oauth2/code/linkedin?code=AQSV...
流没有进一步移动。任何帮助表示赞赏。谢谢。【参考方案2】:
问题/原因是缺少 tokenType。
要重现在org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter
这个地方设置断点:
catch (AuthenticationException failed)
// Authentication failed
unsuccessfulAuthentication(request, response, failed);
return;
然后你会看到failed
= 这个异常:
org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: Error while extracting response for type [class org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: An error occurred reading the OAuth 2.0 Access Token Response: tokenType cannot be null; nested exception is java.lang.IllegalArgumentException: tokenType cannot be null
对此的一个“解决方案”是添加一个添加 tokenType 的转换器。
看看https://github.com/spring-projects/spring-security/issues/5983#issuecomment-430620308 并添加这个调用.tokenEndpoint().accessTokenResponseClient(authorizationCodeTokenResponseClient())
加上authorizationCodeTokenResponseClient()
的实现在提到的github-link (https://github.com/jzheaux/messaging-app/blob/master/client-app/src/main/java/sample/config/SecurityConfig.java#L71) 加上这个类https://github.com/jzheaux/messaging-app/blob/master/client-app/src/main/java/sample/web/CustomAccessTokenResponseConverter.java。
...为了完整起见:这是我在 application.properties 中的配置 sn-p:
spring.security.oauth2.client.registration.linkedin.client-id: ????
spring.security.oauth2.client.registration.linkedin.client-secret: ????
spring.security.oauth2.client.registration.linkedin.scope=r_emailaddress,r_liteprofile
spring.security.oauth2.client.registration.linkedin.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.linkedin.redirect-uri=baseUrl/login/oauth2/code/registrationId
spring.security.oauth2.client.registration.linkedin.client-name = LinkedIn
spring.security.oauth2.client.registration.linkedin.provider=linkedin
spring.security.oauth2.client.registration.linkedin.client-authentication-method = post
spring.security.oauth2.client.provider.linkedin.authorization-uri=https://www.linkedin.com/oauth/v2/authorization
spring.security.oauth2.client.provider.linkedin.token-uri=https://www.linkedin.com/oauth/v2/accessToken
spring.security.oauth2.client.provider.linkedin.user-info-uri=https://api.linkedin.com/v2/me
spring.security.oauth2.client.provider.linkedin.jwk-set-uri =
spring.security.oauth2.client.provider.linkedin.user-name-attribute = id
spring.security.oauth2.client.provider.linkedin.user-info-authentication-method=post
【讨论】:
【参考方案3】:这个问题可以通过WebClientReactiveAuthorizationCodeTokenResponseClient
bean 自定义轻松解决——您需要修改响应并在其中添加"token_type: "Bearer"
字段。这可以使用 ExchangeFilterFunction 来实现。
所以,这里举个例子,让我们创建一个简单的 DTO:
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy::class)
data class Oauth2TokenResponseDTO(
val accessToken: String,
val expiresIn: Int,
val tokenType: String = OAuth2AccessToken.TokenType.BEARER.value
)
然后,在您的响应式安全配置中添加下一个:
private fun modifyResponse(): ExchangeFilterFunction
return ExchangeFilterFunction.ofResponseProcessor response: ClientResponse ->
response.bodyToMono(Oauth2TokenResponseDTO::class.java)
.map objectMapper.writeValueAsString(it)
.map ClientResponse.from(response).body(it).build()
最后一个:
@Bean
fun webClientReactiveAuthorizationCodeTokenResponseClient(): WebClientReactiveAuthorizationCodeTokenResponseClient
val tokenResponseClient = WebClientReactiveAuthorizationCodeTokenResponseClient()
val webClient = WebClient.builder()
.clientConnector(ReactorClientHttpConnector(HttpClient.create().wiretap(true)))
.filter(modifyResponse())
.build()
tokenResponseClient.setWebClient(webClient)
return tokenResponseClient
P.S.:请注意,如果您有其他 oauth2 提供程序 - 您需要在 ExchangeFilterFunction
中实现过滤器方法。
【讨论】:
以上是关于如何让 Linkedin OAuth 在 Spring Boot 中工作的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 iOS SDK 保存 LinkedIn 访问令牌?