Django 授权并获取访问令牌后,如何将用户传回前端客户端?

Django 授权并获取访问令牌后,如何将用户传回前端客户端?,django,reactjs,redux,django-rest-framework,spotify,Django,Reactjs,Redux,Django Rest Framework,Spotify,我有一个Django后端和React/Redux前端,我正在尝试集成SpotifyAPI。我是一个彻头彻尾的django noob,所以请发发慈悲吧。目前,我通过前端的常规ol'anchor标记将用户发送到我的后端。然后,我的后端将用户重定向到Spotify授权页面,然后该页面将他们重定向到另一个页面,该页面将授权代码转换为我现在拥有的访问令牌。然而,这些代码和URL只是将我发送到我的后端API。如何使用此访问令牌让用户返回前端?“我的”代码: 来自django.views.generic.ba

我有一个Django后端和React/Redux前端,我正在尝试集成SpotifyAPI。我是一个彻头彻尾的django noob,所以请发发慈悲吧。目前,我通过前端的常规ol'anchor标记将用户发送到我的后端。然后,我的后端将用户重定向到Spotify授权页面,然后该页面将他们重定向到另一个页面,该页面将授权代码转换为我现在拥有的访问令牌。然而,这些代码和URL只是将我发送到我的后端API。如何使用此访问令牌让用户返回前端?“我的”代码:

来自django.views.generic.base导入重定向视图,TemplateView
来自rest\u framework.response导入响应
从rest_框架导入泛型、视图集和权限
从django.url反向导入
从毛皮进口
导入请求
def生成\授权\ url(请求):
参数={
“客户id”:“,
“响应类型”:“代码”,
“重定向\u uri”:request.build\u绝对\u uri(
反向(“spotify回调”)
),
范围“:”。加入(
[
“用户读取当前正在播放”,
“用户修改播放状态”,
“用户读取播放状态”,
“流媒体”,
“应用程序远程控制”,
“播放列表读取协作”,
“播放列表修改公共”,
'播放列表读取专用',
“播放列表修改专用”,
“用户库修改”,
“用户顶端读取”,
“用户读取播放位置”,
“最近播放的用户读取”,
]
),
}
打印(参数)
url=(
卷起https://accounts.spotify.com/authorize")
.add(参数)
.url
)
打印(url)
返回url
验证头={
“授权”:“基本”
+base64.b64编码(
“:”.encode()
).decode()
}
def句柄_回调(请求):
代码=请求。获取[“代码”]
response=requests.post(
"https://accounts.spotify.com/api/token",
资料={
“授权类型”:“授权代码”,
“代码”:代码,
“重定向\u uri”:request.build\u绝对\u uri(
反向(“spotify回调”)
),
},
headers=AUTH_HEADER,
)
返回response.json()
类SpotifyLoginView(重定向视图):
查询字符串=True
def get_redirect_url(self、*args、**kwargs):
返回生成\授权\ url(self.request)
类SpotifyCallbackView(generics.GenericAPIView):
def get(自我、请求、*args、**kwargs):
打印(处理回调(请求))
返回响应(句柄\回调(请求))

获取访问/刷新令牌后,您可以将用户重定向到前端URL,并通过Spotify的Github帐户(用JS编写,但想法相同)传递令牌值,如中所示:

res.redirect('/#'+
查询字符串({
访问令牌:访问令牌,
刷新\u令牌:刷新\u令牌
})
);

您可以阅读有关身份验证流的更多信息。

但这会在url中发送令牌,不是吗?我只想将它们作为json响应传递,然后将它们保存在本地存储中。但是在你的前端,你可以从url中获取它们,并将它们存储在本地存储中。我要这么做,这看起来有点骇人。另外,我如何处理刷新令牌?似乎我需要将用户发送回服务器,以获得与原始身份验证代码类似的流,而不是将其与刷新令牌一起使用。但是,在类似的真实情况下,用户不知道令牌正在刷新。这是怎么发生的?@Morks你可以在前端处理。如果在响应中获得401状态,则发送新请求并尝试刷新令牌。然后使用新令牌再次发出请求。根据spotify API站点,刷新流与令牌流相同,唯一的区别是使用刷新令牌代替授权码。也就是说,头需要在令牌的POST请求中包含clientId和客户机机密,这就是需要从后端执行请求以不暴露客户机机密的原因。如何能够在不暴露客户机密的情况下从前端完成?
from django.views.generic.base import RedirectView, TemplateView
from rest_framework.response import Response
from rest_framework import generics, viewsets, permissions
from django.urls import reverse
from furl import furl
import requests


def build_authorize_url(request):
    params = {
        "client_id": "<client-id>",
        "response_type": "code",
        "redirect_uri": request.build_absolute_uri(
            reverse("spotify callback")
        ),
        "scope": " ".join(
            [
                'user-read-currently-playing',
                'user-modify-playback-state',
                'user-read-playback-state',
                'streaming',
                'app-remote-control',
                'playlist-read-collaborative',
                'playlist-modify-public',
                'playlist-read-private',
                'playlist-modify-private',
                'user-library-modify',
                'user-top-read',
                'user-read-playback-position',
                'user-read-recently-played',
            ]
        ),
    }
    print(params)

    url = (
        furl("https://accounts.spotify.com/authorize")
        .add(params)
        .url
    )
    print(url)

    return url


AUTH_HEADER = {
    "Authorization": "Basic "
    + base64.b64encode(
        "<my client id>:<my client secret>".encode()
    ).decode()
}


def handle_callback(request):
    code = request.GET["code"]

    response = requests.post(
        "https://accounts.spotify.com/api/token",
        data={
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": request.build_absolute_uri(
                reverse("spotify callback")
            ),
        },
        headers=AUTH_HEADER,
    )

    return response.json()


class SpotifyLoginView(RedirectView):
    query_string = True

    def get_redirect_url(self, *args, **kwargs):
        return build_authorize_url(self.request)


class SpotifyCallbackView(generics.GenericAPIView):
    def get(self, request, *args, **kwargs):
        print(handle_callback(request))

        return Response(handle_callback(request))