Java 使用SpringBoot的LinkedIn身份验证

Java 使用SpringBoot的LinkedIn身份验证,java,spring,spring-boot,spring-security-oauth2,linkedin-api,Java,Spring,Spring Boot,Spring Security Oauth2,Linkedin Api,我试图在我的spring boot应用程序中使用LinkedIn身份验证,我得到以下错误 [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.endpoin

我试图在我的spring boot应用程序中使用LinkedIn身份验证,我得到以下错误

[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;charset=utf-8]; 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

这是我的申请表

spring:
  security:
    oauth2:
      client:
        registration:
          linkedin:
            clientId: CLIENTID
            clientSecret: SECRET
            client-authentication-method: post
            authorization-grant-type: authorization_code
            redirect-uri: http://localhost:8080/login/oauth2/code/linkedin
            scope: r_liteprofile, r_emailaddress,w_member_social

            client-name: Linkedin

        provider:
          linkedin:          
            authorization-uri: https://www.linkedin.com/oauth/v2/authorization
            token-uri: https://www.linkedin.com/oauth/v2/accessToken
            user-info-uri: https://api.linkedin.com/v1/people/~?format=json
            user-name-attribute: id
任何解决这个问题的方法,或者如何使用linkedin在spring boot中进行身份验证的方法,我都遇到了同样的错误

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
在这里,您可以看到linkedin OAuth2提供程序在请求令牌时抱怨
令牌类型不能为null

Google和某些其他第三方身份提供商对发送到用户信息端点的头中的令牌类型名称要求更严格时,就会发生这种情况。默认值为“Bearer”,适用于大多数提供商并与规范相匹配,但如果需要更改它,可以设置security.oauth2.resource.token类型。

为了进行此配置,我们需要引入
spring-security-oauth2-autoconfigure

解决方案1 附属国

org.springframework.boot

这是SpringSecurity5的一个已知错误。作为OAuth2授权提供商,LinkedIn不是一个非常流行的选择。Spring Security与Google和其他提供商完美兼容并不奇怪,但它不符合LinkedIn OAuth2对客户端的要求

5.1。成功响应 授权服务器发出访问令牌和可选刷新令牌,并通过向HTTP响应的实体体添加以下参数来构造响应,状态代码为200(确定):
需要令牌类型。按照第7.1节所述发布的令牌类型。值不区分大小写

token\u type
是必需的参数,但Spring Security不会将其传递到请求中

SecurityConfig
中,您可以通过设置
.tokenEndpoint().accessTokenResponseClient(authorizationCodeTokenResponseClient())
完整的演示代码可在

证券配置
.authorizationEndpoint()
.baseUri(…)
.authorizationRequestRepository(…)
.及()
.tokenpoint()
.accessTokenResponseClient(authorizationCodeTokenResponseClient())
.及()
.redirectionEndpoint()文件
.baseUri(…)
authorizationCodeTokenResponseClient()
private方法
private OAuth2AccessTokenResponseClient授权CodeTokenResponseClient(){
OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter=
新的OAuth2AccessTokenResponseHttpMessageConverter();
setTokenResponseConverter(新的CustomAccessTokenResponseConverter())//https://github.com/jzheaux/messaging-app/blob/392a1eb724b7447928c750fb2e47c22ed26d144e/client-app/src/main/java/sample/web/CustomAccessTokenResponseConverter.java#L35
RestTemplate RestTemplate=新的RestTemplate(Arrays.asList(
新表单HttpMessageConverter(),tokenResponseHttpMessageConverter));
setErrorHandler(新的OAuth2ErrorResponseErrorHandler());
DefaultAuthorizationCodeTokenResponseClient tokenResponseClient=新的DefaultAuthorizationCodeTokenResponseClient();
tokenResponseClient.setRestOperations(restTemplate);
返回tokenResponseClient;
}
自定义转换器
package com.fermedu.resume.config;
导入org.springframework.core.convert.converter.converter;
导入org.springframework.security.oauth2.core.OAuth2AccessToken;
导入org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
导入org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
导入org.springframework.util.StringUtils;
导入java.util.*;
导入java.util.stream.collector;
导入java.util.stream.stream;
公共类CustomAccessTokenResponseConverter实现转换器{
私有静态最终设置令牌\响应\参数\名称=Stream.of(
OAuth2ParameterNames.ACCESS\u令牌,
OAuth2ParameterNames.TOKEN_类型,
OAuth2ParameterNames.EXPIRES_IN,
OAuth2ParameterNames.REFRESH_令牌,
OAuth2ParameterNames.SCOPE).collect(Collectors.toSet());
@凌驾
公共OAuth2Access令牌响应转换(映射令牌响应参数){
String accessToken=tokenResponseParameters.get(OAuth2ParameterNames.ACCESS\u令牌);
OAuth2AccessToken.TokenType accessTokenType=OAuth2AccessToken.TokenType.Bear;
长呼气指数=0;
if(tokenResponseParameters.containsKey(OAuth2ParameterNames.EXPIRES_IN)){
试一试{
expiresIn=Long.valueOf(tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN));
}catch(NumberFormatException ex){}
}
Set scopes=Collections.emptySet();
if(tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)){
String scope=tokenResponseParameters.get(OAuth2ParameterNames.scope);
scopes=Arrays.stream(StringUtils.delimitedListToStringaray(scope,“”).collect(Collectors.toSet());
}
Map additionalParameters=新建LinkedHashMap();
tokenResponseParameters.entrySet().stream()
.filter(e->!令牌\响应\参数\名称。包含(e.getKey())
.forEach(e->additionalParameters.put(e.getKey(),e.getValue());
返回OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(accessTokenType)
.expiresIn(expiresIn)
.作用域(作用域)
.附加参数(附加参数)
.build();
}
}

此解决方案2适用于我。

请注意浏览器上的“网络”选项卡,以检查作为响应返回的确切内容。如果没有链接的应用程序,很难对其进行测试并确定问题。确认
security.oauth2.resource.token-type=Bearer