Spring Security Oauth2.0报错
org.springframework.security.authentication.InsufficientAuthenticationException: Authentication is required to obtain an access token (anonymous not allowed)
anonymous这个单词是匿名的意思,也就是说不允许匿名访问access token。
出问题的代码如下:
@Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) { OAuth2RestTemplate template = new OAuth2RestTemplate(details, context); AuthorizationCodeAccessTokenProvider authCodeProvider = new AuthorizationCodeAccessTokenProvider(); authCodeProvider.setStateMandatory(false); AccessTokenProviderChain provider = new AccessTokenProviderChain( Arrays.asList(authCodeProvider)); template.setAccessTokenProvider(provider); return template; }
google了很久都没有解决问题。最后在一个英文评论里找到了解决方法。
翻译过来,原因是AccessTokenProvider接口有多个实现,OAuth2RestTemplate 实例化了 AccessTokenProviderChain,是为了重用login context。但是如果客户端没有login画面的话,就会报上面的错。
而我的客户端正好是没有login画面的!!!解决方法就是将上面的代码改为:
@Bean public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) { OAuth2RestTemplate template = new OAuth2RestTemplate(details, context); template.setAccessTokenProvider(new AuthorizationCodeAccessTokenProvider()); return template; }
英文原版如下:
I had the same problem and concluded that the AccessTokenProvider interface, which has multiple implementors is the culprit. By default, the OAuth2RestTemplate instantiates the AccessTokenProviderChain which tries to re-use the existing login context. However, if no such login exists, this is bound to fail. Try restTemplate.setAccessTokenProvider(new ResourceOwnerPasswordAccessTokenProvider()); in your factory method. This uses a token provider which owns its credentials and doesn't reference the thread local SecurityContextHolder in its implementation at all.
※由于我用的是code方式换取token,所以它这里的ResourceOwnerPasswordAccessTokenProvider要改成AuthorizationCodeAccessTokenProvider。不然会报下面的错:
java.lang.ClassCastException: org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails cannot be cast to org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails