使用 spring-boot-starter-oauth2-client 检索 OAuth2 3-legged 身份验证的访问令牌

Posted

技术标签:

【中文标题】使用 spring-boot-starter-oauth2-client 检索 OAuth2 3-legged 身份验证的访问令牌【英文标题】:Retrieving the access token of a OAuth2 3-legged authentication using spring-boot-starter-oauth2-client 【发布时间】:2019-10-25 07:15:52 【问题描述】:

我想知道如何使用 org.springframework.boot:spring-boot-starter-oauth2-client 提供的功能在 Spring Boot 3-legged 身份验证中检索访问令牌

我可以使用常规的RestTemplate 调用来获取访问令牌。

我尝试按照https://github.com/wonwoo/spring-boot-oauth2-login 中的示例使用spring-boot-starter-oauth2-client 功能获取相同的访问令牌。

我能够检索服务器提供的代码,但我不知道如何获取访问令牌。

我的代码如下所示:

application.properties 中的属性:

spring.security.oauth2.client.registration.my-client-name-here.client-id=__client_id_here__
spring.security.oauth2.client.registration.my-client-name-here.client-secret=__client_secret_here__
spring.security.oauth2.client.registration.my-client-name-here.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-name-here.redirect-uri-template=http://localhost:8080/authentication/3leggedtoken/callback
spring.security.oauth2.client.registration.my-client-name-here.scope=data:read
spring.security.oauth2.client.registration.my-client-name-here.client-name=__client_name_here__
spring.security.oauth2.client.registration.my-client-name-here.client-authentication-method=POST
spring.security.oauth2.client.provider.my-client-name-here.token-uri=https://example.com/api/token
spring.security.oauth2.client.provider.my-client-name-here.authorization-uri=https://example.com/api/authorize
spring.security.oauth2.client.provider.my-client-name-here.user-info-uri=
spring.security.oauth2.client.provider.my-client-name-here.user-name-attribute=

login.html中的Thymeleaf模板:

<div th:each="registration: $registrations">
  <a th:href="@$registration.uri">
      Sign in with [[$registration.clientName]]
  </a>
</div>

SecurityConfig.java中的配置:

@Configuration
@EnableWebSecurity
public class SegurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http_security) throws Exception 
        http_security.authorizeRequests().requestMatchers(PathRequest.toStaticResources().atCommonLocations())
                .permitAll().antMatchers("/authentication/**").permitAll().anyRequest().authenticated().and().oauth2Login()
                .loginPage("/authentication/login").permitAll();
    

AuthenticationController.java 中的控制器:

@Controller
public class AuthenticationController 

    @Autowired
    OAuth2AuthorizedClientService clientService;

    @Autowired
    InMemoryClientRegistrationRepository clientRegistrationRepository;

    @GetMapping("authentication/login")
    public String login(Model model) 
        List<Registration> registrations = StreamSupport.stream(clientRegistrationRepository.spliterator(), true)
                .map(clientRegistration -> new Registration(clientRegistration.getRegistrationId(),
                        OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/"
                                + clientRegistration.getRegistrationId(),
                        clientRegistration.getClientName()))
                .collect(Collectors.toList());
        model.addAttribute("registrations", registrations);
        return "authentication/login";
    

    @GetMapping("authentication/3leggedtoken/callback")
    public String accessToken(Model model, @RequestParam("code") String code)      
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) 
            OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
            String clientRegistrationId = oauthToken.getAuthorizedClientRegistrationId();
            OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(clientRegistrationId,
                    oauthToken.getName());
            return client.getAccessToken().getTokenValue();
        
        return null;
    

应用成功创建到服务器认证页面的链接,并在登录后回调重定向URI。

回调中返回的代码是正确的

public String accessToken(Model model, @RequestParam("code") String code) ...

但身份验证的类型不是OAuth2AuthenticationToken

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

但类型为AnonymousAuthenticationToken

org.springframework.security.authentication.AnonymousAuthenticationToken@ef72fdb1:
   Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true;
   Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364:
       RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: D8FFF6F20C14791E505B8B86648F7E1B;
       Granted Authorities: ROLE_ANONYMOUS

我应该如何获取访问令牌?以及我应该如何访问它以在以下请求中传递它?

提前致谢!

【问题讨论】:

【参考方案1】:

尝试删除@GetMapping("authentication/3leggedtoken/callback")端点并将其注册为bean。像这样:

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.web.context.annotation.RequestScope;

import sample.api.facebook.Facebook;

@Configuration
public class SocialConfig 

    private final static Logger LOG = LoggerFactory.getLogger(SocialConfig.class);

    @Bean
    @RequestScope
    public Facebook facebook(OAuth2AuthorizedClientService clientService) 
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String accessToken = null;
        if (authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) 
            OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
            String clientRegistrationId = oauthToken.getAuthorizedClientRegistrationId();
            if (clientRegistrationId.equals("facebook")) 
                OAuth2AuthorizedClient client =
                    clientService.loadAuthorizedClient(clientRegistrationId, oauthToken.getName());
                accessToken = client.getAccessToken().getTokenValue();

                LOG.error(accessToken);
            
        
        return new Facebook(accessToken);
    


然后按照这个教程from one of Spring oauth2 developers,它帮助我将获取 Facebook 令牌集成到我的项目中。

【讨论】:

以上是关于使用 spring-boot-starter-oauth2-client 检索 OAuth2 3-legged 身份验证的访问令牌的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)