8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Spotify API の簡単な使い方-ログイン機能-

Last updated at Posted at 2019-12-06

#RailsとJsでSpotifyAPIをたたいてみる

###環境・前提条件
ruby 2.6.2
rails 5.2.4

###この記事に書いてあること

  • ユーザーを認証し、ユーザーデータにアクセスするための承認を取得する
  • Web APIエンドポイントからデータを取得する。
    下記のURLはSpotifyAPIの公式ドキュメントです。公式ドキュメントとやっていることは同じですが、この記事ではわかりやすく進行していきます。

###参考URL
公式ドキュメント
https://developer.spotify.com/documentation/web-api/quick-start/
公式github
https://github.com/spotify/web-api-auth-examples

###この記事でできること
アプリのログイン→Spotifyログイン

giitaよう.gif

###対象者

  • Spotify APIをたたきたいけど、どうやってたたけばいいか分からないAPI初心者
  • ドキュメント読むの難しいと感じている方
  • Spotify会員
  • deviseを使ってログイン機能が作成できる方

###今回取得するトークンについて❶

例えばWEB PLAYBACK SDKを使いたいと思ったとき、
下記のソースコードをコピペすればプレイヤーを使用できます。音も鳴るよ♬
ただ参考URLで取得したトークンだと1時間で切れてしまうので参考URLで取得したAccessTokenのところを1時間に一回手動で書き換えなくてはいけません。そんなの無理ー(⌒-⌒; )って感じですよね!
そこで登場するのが今回取得するトークンなんです。

index.html.erb

<!DOCTYPE html>
<html>
<head>
  <title>Spotify Web Playback SDK Quick Start Tutorial</title>
</head>
<body>
  <h1>Spotify Web Playback SDK Quick Start Tutorial</h1>
  <h2>Open your console log: <code>View > Developer > JavaScript Console</code></h2>

  <script src="https://sdk.scdn.co/spotify-player.js"></script>
  <script>
    window.onSpotifyWebPlaybackSDKReady = () => {
      const token = '参考URLで取得したAccessToken';
      const player = new Spotify.Player({
        name: 'Web Playback SDK Quick Start Player',
        getOAuthToken: cb => { cb(token); }
      });

      // Error handling
      player.addListener('initialization_error', ({ message }) => { console.error(message); });
      player.addListener('authentication_error', ({ message }) => { console.error(message); });
      player.addListener('account_error', ({ message }) => { console.error(message); });
      player.addListener('playback_error', ({ message }) => { console.error(message); });

      // Playback status updates
      player.addListener('player_state_changed', state => { console.log(state); });

      // Ready
      player.addListener('ready', ({ device_id }) => {
        console.log('Ready with Device ID', device_id);
      });

      // Not Ready
      player.addListener('not_ready', ({ device_id }) => {
        console.log('Device ID has gone offline', device_id);
      });

      // Connect to the player!
      player.connect();
    };
  </script>
</body>
</html>

###今回取得するトークンについて❷
Spotifyが用意しているトークンの種類は3種類あります。
下記公式ドキュメントですので、目を通してみて下さい。
https://developer.spotify.com/documentation/general/guides/authorization-guide/

今回取得するものは上記のURLの一番下のものです。
Client Credentials Flowは時間が経つと切れてしましますが、手動でコードを直さなくてもいいような仕様となります。3種類の中でも一番簡単でお手軽ですね♬

###手順❶
Spotify API公式ドキュメントのDASHBOADからアプリを作成し、
ClientID,SecretIDを取得しましょう。
スクリーンショット 2019-12-06 13.22.43.png
スクリーンショット 2019-12-06 13.25.26.png

アプリを作成したらClientID,SecretIDを確認しましょう。
次に、ページ右にあるEDIT SETTINGからRedirect URIsを登録しよう。
スクリーンショット 2019-12-06 13.29.11.png
スクリーンショット 2019-12-06 13.34.45.png

###手順❷
deviseを使ってログイン画面を作る。
おなじみdevise先生です♬

Gemfile
gem 'devise'

$ bundle install
$ rails g devise:install

$ rails g devise User
$ rails db:migrate
スクリーンショット 2019-12-05 12.30.58.png

application.html.erb
<!DOCTYPE html>
<html>

<head>
  <title>Authorization</title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>
  <%= include_gon %>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>

<body>
  <% if user_signed_in? %>
  <ul class="navbar">
    <li class="nav-item item">
      <%= link_to "Log out", destroy_user_session_path, method: :delete, class:"nav-link" %>
    </li>
  </ul>
  <% else %>
  <ul class="navbar">
    <li class="nav-item item">
      <%= link_to "Sign up", new_user_registration_path, class:"nav-link" %>
    </li>
    <li class="nav-item item">
      <%= link_to "Log in", new_user_session_path, class:"nav-link" %>
    </li>
  </ul>
  <% end %>
  <%= yield %>
</body>

</html>
application_controller.rb
class ApplicationController < ActionController::Base
    def after_sign_in_path_for(resource)
        if user_signed_in?
            spotify_login_path
        end    
    end
    def after_sign_out_path_for(resource)
        new_user_session_path
    end        
end

###手順❸
APIキーを管理しましょう。

Gemfile
gem 'gon'
gem 'dotenv-rails'

*補足:gonはrailsのコントローラーで指定した変数をJsに持っていける便利gemです♬
    dotenv-railsは.envファイルを管理するgemです♬

$ bundle install

$ rails g controller users

users_controller.rb
class UsersController < ApplicationController
    def spotify_login
        gon.client_id = ENV['SPOTIFY_CLIENT_ID'];
        gon.redirect_uri = ENV["SPOTIFY_REDIRECT_URI"];
    end
end

APIキーは環境変数にして、
.envファイルを作成し、その中に入れましょう。

.env
SPOTIFY_CLIENT_ID=your client ID
SPOTIFY_SECRET_ID=your secret ID
SPOTIFY_REDIRECT_URI=http://localhost:3000/tests/
spotify_login.html.erb
<!doctype html>
<html>

<head>
    <title>Example of the Implicit Grant flow with Spotify</title>
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    <style type="text/css">
        #login,
        #loggedin {
            display: none;
        }

        .text-overflow {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            width: 500px;
        }
    </style>
</head>

<body>
    <div class="gradation">
        <div class="container">
            <div id="login">
                <br>
                <br>
                <h1>This is Spotify Authentication</h1>
                <div class="text-center"><button id="login-button" class="btn btn-primary">Log in with Spotify</button>
                </div>
            </div>
            <div id="loggedin">
                <div id="user-profile">
                </div>
                <div id="oauth">
                </div>
            </div>
        </div>
    </div>
    <script id="user-profile-template" type="text/x-handlebars-template">
        <h1>Logged in as {{display_name}}</h1>
        <div class="media">
        <div class="pull-left">
            <img class="media-object" width="150" src="{{images.0.url}}" />
        </div>
        <div class="media-body">
            <dl class="dl-horizontal">
            <dt>Display name</dt><dd class="clearfix">{{display_name}}</dd>
            <dt>Id</dt><dd>{{id}}</dd>
            <dt>Email</dt><dd>{{email}}</dd>
            <dt>Spotify URI</dt><dd><a href="{{external_urls.spotify}}">{{external_urls.spotify}}</a></dd>
            <dt>Link</dt><dd><a href="{{href}}">{{href}}</a></dd>
            <dt>Profile Image</dt><dd class="clearfix"><a href="{{images.0.url}}">{{images.0.url}}</a></dd>
            <dt>Country</dt><dd>{{country}}</dd>
            </dl>
        </div>
        </div>

    </script>
    <script id="oauth-template" type="text/x-handlebars-template">
        <h2>oAuth info</h2>
        <dl class="dl-horizontal">
        <dt>Access token</dt><dd class="text-overflow">{{access_token}}</dd>
        </dl>
    </script>

    <script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0-alpha.1/handlebars.min.js"></script>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>

    <script>
        (function () {

            var stateKey = 'spotify_auth_state';

            /**
             * Obtains parameters from the hash of the URL
             * @return Object
             */
            function getHashParams() {
                var hashParams = {};
                var e, r = /([^&;=]+)=?([^&;]*)/g, q = window.location.hash.substring(1);
                while (e = r.exec(q)) {
                    hashParams[e[1]] = decodeURIComponent(e[2]);
                }
                return hashParams;
            }

            /**
             * Generates a random string containing numbers and letters
             * @param  {number} length The length of the string
             * @return {string} The generated string
             */
            function generateRandomString(length) {
                var text = '';
                var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

                for (var i = 0; i < length; i++) {
                    text += possible.charAt(Math.floor(Math.random() * possible.length));
                }
                return text;
            };

            var userProfileSource = document.getElementById('user-profile-template').innerHTML,
                userProfileTemplate = Handlebars.compile(userProfileSource),
                userProfilePlaceholder = document.getElementById('user-profile');

            oauthSource = document.getElementById('oauth-template').innerHTML,
                oauthTemplate = Handlebars.compile(oauthSource),
                oauthPlaceholder = document.getElementById('oauth');

            var params = getHashParams();

            var access_token = params.access_token,
                state = params.state,
                storedState = localStorage.getItem(stateKey);
            console.log("-------------------------")
            console.log(access_token);
            if (access_token && (state == null || state !== storedState)) {
                alert('There was an error during the authentication');
            } else {
                localStorage.removeItem(stateKey);
                if (access_token) {
                    $.ajax({
                        url: 'https://api.spotify.com/v1/me',
                        headers: {
                            'Authorization': 'Bearer ' + access_token
                        },
                        success: function (response) {
                            userProfilePlaceholder.innerHTML = userProfileTemplate(response);
                            console.log(response);
                            $('#login').hide();
                            $('#loggedin').show();
                        }
                    });
                } else {
                    $('#login').show();
                    $('#loggedin').hide();
                }

                document.getElementById('login-button').addEventListener('click', function () {

                    var client_id = gon.client_id; // Your client id
                    var redirect_uri = gon.redirect_uri; // Your redirect uri

                    var state = generateRandomString(16);

                    localStorage.setItem(stateKey, state);
                    var scope = 'streaming user-read-private user-read-email playlist-modify-private';

                    var url = 'https://accounts.spotify.com/authorize';
                    url += '?response_type=token';
                    url += '&client_id=' + encodeURIComponent(client_id);
                    url += '&scope=' + encodeURIComponent(scope);
                    url += '&redirect_uri=' + encodeURIComponent(redirect_uri);
                    url += '&state=' + encodeURIComponent(state);

                    window.location = url;
                }, false);
            }
        })();
    </script>

</html>

###手順❹
ログイン後のviewを作成しましょう。
$ rails g conrtoller tests

tests_controller.rb
class TestsController < ApplicationController
    def index
    end
end
index.html.erb
ログインできました。
お疲れ様でした!
routes.rb
Rails.application.routes.draw do
  devise_for :users
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  get 'users/spotify_login', to: 'users#spotify_login', as: 'spotify_login'
  resources :tests, only: [:index]
end

###手順❺
####完成!
ログインしてみましょう。
access_tokenは遷移先(今回でいうとtests_path)のURLに表示されています。
URLのxxxのところがaccess_tokenです。
expires_in=3600は、トークンの期限を表示しています。3600秒=1時間です。1時間でaccess_tokenが切れるのでユーザーは1時間ごとにログインをし直しましょう♬
http://localhost:3000/tests/#access_token=xxx&token_type=Bearer&expires_in=3600&state=caGLGQ8xzz1yYbH7

###Github
全コードは下記のgithubを参照ください♬
https://github.com/natan777natan/authorization

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?