如何将 Spring Boot 与 Spotify OAuth 2 身份验证集成

How to integrate Spring Boot with Spotify OAuth 2 authentication

我是 spring 引导和 spring 安全方面的新手。所以我从一些教程开始。现在我想在我的示例应用程序中将 oauth 身份验证与 spotify 集成。

我在 spring.io 的 spring boot oauth 2 教程中指导了我。将解释我如何将 oauth 与 facebook 和 github 集成。我自定义了 application.yml 来 spotify 配置,但它没有用。

application.yml

security:
  oauth2:
    client:
      clientId: <my-client-id>
      clientSecret: <my-secret>
      accessTokenUri: https://accounts.spotify.com/api/token
      userAuthorizationUri: https://accounts.spotify.com/authorize
      tokenName: oauth_token
      authenticationScheme: query
      clientAuthenticationScheme: form
      scope: user-read-private, user-read-email
    resource:
      userInfoUri: https://api.spotify.com/v1/me

SpotifyOAuthApplication.java

package sh.stern.SpotifyOAuth;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

@SpringBootApplication
@EnableOAuth2Sso
@RestController
public class SpotifyOAuthApplication extends WebSecurityConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(SpotifyOAuthApplication.class, args);
    }

    @RequestMapping("/user")
    public Principal user(Principal principal) {
        return principal;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/", "/login**", "/webjars/**", "/error**")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and().logout().logoutSuccessUrl("/").permitAll()
                .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

/resources/static/index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Demo</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<h1>Demo</h1>
<div class="container">
    <div class="container unauthenticated">
        With Spotify: <a href="/login">click here</a>
    </div>
    <div class="container authenticated" style="display:none">
        Logged in as: <span id="user"></span>
        <div>
            <button onClick="logout()" class="btn btn-primary">Logout</button>
        </div>
    </div>
    <script type="text/javascript">
      $.get("/user", function(data) {
        $("#user").html(data.userAuthentication.details.name);
        $(".unauthenticated").hide()
        $(".authenticated").show()
      });

      var logout = function() {
        $.post("/logout", function() {
          $("#user").html('');
          $(".unauthenticated").show();
          $(".authenticated").hide();
        });
        return true;
      }

      $.ajaxSetup({
        beforeSend : function(xhr, settings) {
          if (settings.type == 'POST' || settings.type == 'PUT'
            || settings.type == 'DELETE') {
            if (!(/^http:.*/.test(settings.url) || /^https:.*/
              .test(settings.url))) {
              // Only send the token to relative URLs i.e. locally.
              xhr.setRequestHeader("X-XSRF-TOKEN",
                Cookies.get('XSRF-TOKEN'));
            }
          }
        }
      });
    </script>
    <script type="text/javascript" src="/webjars/js-cookie/js.cookie.js"></script>
</div>
</body>
</html>

build.gradle

plugins {
    id 'org.springframework.boot' version '2.1.5.RELEASE'
    id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'sh.stern'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

    compile group: 'org.springframework.security.oauth.boot', name: 'spring-security-oauth2-autoconfigure', version: '2.1.5.RELEASE'
    compile group: 'org.webjars', name: 'jquery', version: '3.4.1'
    compile group: 'org.webjars', name: 'js-cookie', version: '2.1.0'
    compile group: 'org.webjars', name: 'bootstrap', version: '4.3.1'
    compile group: 'org.webjars', name: 'webjars-locator-core', version: '0.37'
}

如果我启动我的应用程序并在 localhost:8080 上打开 Web 应用程序,我将被重定向到 Spotify。我登录到我的 spotify 帐户并被重定向到我的应用程序,但在重定向后我收到以下错误:

2019-05-24 23:00:17.564  WARN 55176 --- [io-8080-exec-10] o.s.b.a.s.o.r.UserInfoTokenServices      : Could not fetch user details: class org.springframework.web.client.HttpClientErrorException$Unauthorized, 401 Unauthorized

我是否配置错误 application.yml?

我能找到问题所在,application.yml 配置错误。似乎 tokenName 是错误的。我删除了这个属性,现在它可以工作了。

配置现在看起来像这样:

security:
  oauth2:
    client:
      clientId: <my-client-id>
      clientSecret: <my-client-secret>
      accessTokenUri: https://accounts.spotify.com/api/token
      userAuthorizationUri: https://accounts.spotify.com/authorize
      authenticationScheme: query
      clientAuthenticationScheme: form
      scope: user-read-private, user-read-email
    resource:
      userInfoUri: https://api.spotify.com/v1/me