我遇到了一个非常奇怪的问题,很可能是由 linkedin API 引起的。我已经像任何人一样将 linkedin 配置为提供商。 PFA 片段。
问题很奇怪: 为了从端点获取用户信息,我需要在范围内使用
openid
。现在,即使范围是 openid
,linkedin 也会返回一个不透明令牌并且不提供 JWKs URI。
通过在范围内查找
openid
,spring的OAuth2LoginAuthenticationProvider拒绝它并询问OidcAuthorizationCodeAuthenticationProvider(参见它调用createOidcToken
的行,它在内部查找JWKs URI)问题是,Linkedin首先不会返回JWT .
重要提示:我尝试最初保留 openid 范围并在调试点中删除,以便 OAuth2LoginAuthenticationProvider 接受它,并且它可以工作。
我正在尝试创建我的 CustomAuthenticationProvider,但 Spring 无法注入依赖项。
文件*
application.yml
spring:
security:
oauth2:
client:
registration:
linkedin:
provider: linkedin
client-id: ${LINKEDIN_CLIENT_ID}
client-secret: ${LINKEDIN_CLIENT_SECRET}
client-authentication-method: client_secret_post
authorization-grant-type: 'authorization_code'
redirect-uri: '{baseUrl}/login/oauth2/code/linkedin'
scope:
- profile
- email
- openid
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/v2/userinfo
user-name-attribute: sub
配置文件
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/login", "/resources/**", "/logout")
.permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauthLoginConfig -> oauthLoginConfig
.tokenEndpoint(tokenEndpointConfig -> {
tokenEndpointConfig.accessTokenResponseClient(linkedinTokenResponseClient());
}));
return httpSecurity.build();
}
private static DefaultAuthorizationCodeTokenResponseClient linkedinTokenResponseClient() {
var defaultMapConverter = new DefaultMapOAuth2AccessTokenResponseConverter();
Converter<Map<String, Object>, OAuth2AccessTokenResponse> linkedinMapConverter = tokenResponse -> {
var withTokenType = new HashMap<>(tokenResponse);
withTokenType.put(OAuth2ParameterNames.TOKEN_TYPE, OAuth2AccessToken.TokenType.BEARER.getValue());
return defaultMapConverter.convert(withTokenType);
};
var httpConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
httpConverter.setAccessTokenResponseConverter(linkedinMapConverter);
var restOperations = new RestTemplate(List.of(new FormHttpMessageConverter(), httpConverter));
restOperations.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
var client = new DefaultAuthorizationCodeTokenResponseClient();
client.setRestOperations(restOperations);
return client;
}
自定义身份验证提供程序
从这里复制,除了删除第98到105行。
简短的回答:保留 Spring 默认值,并在客户端上仅读取 ID 令牌(或非 OpenID 提供商的用户信息)。客户端仅应使用访问令牌来授权对资源服务器的请求(不应该尝试解析它)。
openid
范围要求 OpenID 提供者返回 ID-token,根据 OpenID 规范,该令牌必须是 JWT。但该规范对访问令牌格式绝对没有任何限制。 LinkedIn 很可能打算限制其向自己的 API 发出的访问令牌的使用(您可以将其用作您自己的授权服务器的身份源,而不是用作您的资源服务器的免费授权服务器)。