Browse Source
Implement User Authorization
Implement User Authorization
Completed step 1 of the Authorization Code Flow documented by the Spotify API.master
Chris
7 years ago
5 changed files with 189 additions and 2 deletions
-
1musicvis/settings.py
-
5requirements.txt
-
132spotifyvis/templates/spotifyvis/index.html
-
3spotifyvis/urls.py
-
50spotifyvis/views.py
@ -1,10 +1,15 @@ |
|||||
astroid==1.6.3 |
astroid==1.6.3 |
||||
|
certifi==2018.4.16 |
||||
|
chardet==3.0.4 |
||||
Django==2.0.5 |
Django==2.0.5 |
||||
djangorestframework==3.8.2 |
djangorestframework==3.8.2 |
||||
|
idna==2.6 |
||||
isort==4.3.4 |
isort==4.3.4 |
||||
lazy-object-proxy==1.3.1 |
lazy-object-proxy==1.3.1 |
||||
mccabe==0.6.1 |
mccabe==0.6.1 |
||||
pylint==1.8.4 |
pylint==1.8.4 |
||||
pytz==2018.4 |
pytz==2018.4 |
||||
|
requests==2.18.4 |
||||
six==1.11.0 |
six==1.11.0 |
||||
|
urllib3==1.22 |
||||
wrapt==1.10.11 |
wrapt==1.10.11 |
@ -0,0 +1,132 @@ |
|||||
|
<!doctype html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Example of the Authorization Code 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="container"> |
||||
|
<div id="login"> |
||||
|
<h1>This is an example of the Authorization Code flow</h1> |
||||
|
<a href="/login" class="btn btn-primary">Log in with Spotify</a> |
||||
|
</div> |
||||
|
<div id="loggedin"> |
||||
|
<div id="user-profile"> |
||||
|
</div> |
||||
|
<div id="oauth"> |
||||
|
</div> |
||||
|
<button class="btn btn-default" id="obtain-new-token">Obtain new token using the refresh token</button> |
||||
|
</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> |
||||
|
<dt>Refresh token</dt><dd class="text-overflow">{{refresh_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() { |
||||
|
/** |
||||
|
* 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; |
||||
|
} |
||||
|
var userProfileSource = document.getElementById('user-profile-template').innerHTML, |
||||
|
userProfileTemplate = Handlebars.compile(userProfileSource), |
||||
|
userProfilePlaceholder = document.getElementById('user-profile'); |
||||
|
var oauthSource = document.getElementById('oauth-template').innerHTML, |
||||
|
oauthTemplate = Handlebars.compile(oauthSource), |
||||
|
oauthPlaceholder = document.getElementById('oauth'); |
||||
|
var params = getHashParams(); |
||||
|
var access_token = params.access_token, |
||||
|
refresh_token = params.refresh_token, |
||||
|
error = params.error; |
||||
|
if (error) { |
||||
|
alert('There was an error during the authentication'); |
||||
|
} else { |
||||
|
if (access_token) { |
||||
|
// render oauth info |
||||
|
oauthPlaceholder.innerHTML = oauthTemplate({ |
||||
|
access_token: access_token, |
||||
|
refresh_token: refresh_token |
||||
|
}); |
||||
|
$.ajax({ |
||||
|
url: 'https://api.spotify.com/v1/me', |
||||
|
headers: { |
||||
|
'Authorization': 'Bearer ' + access_token |
||||
|
}, |
||||
|
success: function(response) { |
||||
|
userProfilePlaceholder.innerHTML = userProfileTemplate(response); |
||||
|
$('#login').hide(); |
||||
|
$('#loggedin').show(); |
||||
|
} |
||||
|
}); |
||||
|
} else { |
||||
|
// render initial screen |
||||
|
$('#login').show(); |
||||
|
$('#loggedin').hide(); |
||||
|
} |
||||
|
document.getElementById('obtain-new-token').addEventListener('click', function() { |
||||
|
$.ajax({ |
||||
|
url: '/refresh_token', |
||||
|
data: { |
||||
|
'refresh_token': refresh_token |
||||
|
} |
||||
|
}).done(function(data) { |
||||
|
access_token = data.access_token; |
||||
|
oauthPlaceholder.innerHTML = oauthTemplate({ |
||||
|
access_token: access_token, |
||||
|
refresh_token: refresh_token |
||||
|
}); |
||||
|
}); |
||||
|
}, false); |
||||
|
} |
||||
|
})(); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
@ -1,6 +1,52 @@ |
|||||
from django.shortcuts import render |
|
||||
|
from django.shortcuts import render, redirect |
||||
from django.http import HttpResponse |
from django.http import HttpResponse |
||||
|
import math |
||||
|
import random |
||||
|
import requests |
||||
|
import os |
||||
|
import urllib |
||||
|
|
||||
|
def generate_random_string(length): |
||||
|
"""Generates a random string of a certain length |
||||
|
|
||||
|
Args: |
||||
|
length: the desired length of the randomized string |
||||
|
|
||||
|
Returns: |
||||
|
A random string |
||||
|
""" |
||||
|
rand_str = "" |
||||
|
possible_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" |
||||
|
|
||||
|
for _ in range(length): |
||||
|
rand_str += possible_chars[random.randint(0, len(possible_chars) - 1)] |
||||
|
|
||||
|
return rand_str |
||||
|
|
||||
|
|
||||
# Create your views here. |
# Create your views here. |
||||
def index(request): |
def index(request): |
||||
return HttpResponse("You're at the index") |
|
||||
|
return render(request, 'spotifyvis/index.html') |
||||
|
|
||||
|
|
||||
|
def login(request): |
||||
|
|
||||
|
state_str = generate_random_string(16) |
||||
|
# use a randomly generated state string to prevent cross-site request forgery attacks |
||||
|
request.session['state_string'] = state_str |
||||
|
|
||||
|
payload = { |
||||
|
'client_id': os.environ['SPOTIFY_CLIENT_ID'], |
||||
|
'response_type': 'code', |
||||
|
'redirect_uri': 'http://localhost:8000/callback', |
||||
|
'state': state_str, |
||||
|
'scope': 'user-library-read', |
||||
|
'show_dialog': False |
||||
|
} |
||||
|
|
||||
|
params = urllib.parse.urlencode(payload) # turn the payload dict into a query string |
||||
|
authorize_url = "https://accounts.spotify.com/authorize/?{}".format(params) |
||||
|
return redirect(authorize_url) |
||||
|
|
||||
|
def callback(request): |
||||
|
return HttpResponse("At callback") |
Write
Preview
Loading…
Cancel
Save
Reference in new issue