无法刷新Spotify令牌iOS SDK

时间:2017-03-05 22:34:23

标签: node.js swift express swift3 spotify

我对使用刷新令牌服务的方式感到困惑。在我的应用程序中有一个包含许多播放列表的部分。当用户点击播放列表时,它会运行以下代码:

 func checkAuth() {
    print("checking auth")
    let auth = SPTAuth.defaultInstance()
    //print(auth!.session.isValid())
    if auth!.session == nil {
        print("no auth")
        if auth!.hasTokenRefreshService {
            print("refresh token if session == nil")
            self.renewTokenAndShowPlayer()
            return
        } else {
            self.performSegue(withIdentifier: "LoginControllerSegue", sender: nil)
        }
        return
    }
    if auth!.session.isValid() && firstLoad {
        // It's still valid, show the player.
        print("valid auth")
        self.showPlayer()
        return
    }

    if auth!.hasTokenRefreshService {
        print("refresh token")
        self.renewTokenAndShowPlayer()
        return
    }
}


    func renewTokenAndShowPlayer() {
    SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
        SPTAuth.defaultInstance().session = session
        if error != nil {
            print("Refreshing token failed.")
            print("*** Error renewing session: \(error)")
            self.performSegue(withIdentifier: "LoginControllerSegue", sender: nil)
            return
        }
        self.showPlayer()
    }
}

所以,让我们说用户还没有登录,他们转到登录播放器,然后进行身份验证。

稍后,当他们关闭播放器并点击其他播放列表时,会再次将其带到登录屏幕。这是为什么?

我相信我的刷新令牌服务有效,因为无论何时在有人登录后调用它,我的服务器都会成为/swap 200。此外,只有在登录Spotify后有人回到应用程序(LoginViewController)时才会调用此操作,为什么会这样?

以下是我的登录页面的代码:

import UIKit
import WebKit

class LoginViewController: UIViewController, SPTStoreControllerDelegate, WebViewControllerDelegate {

    @IBOutlet weak var statusLabel: UILabel!
    var authViewController: UIViewController?
    var firstLoad: Bool!
    var Information: [String:String]?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.statusLabel.text = ""
        self.firstLoad = true

        let auth = SPTAuth.defaultInstance()


        NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)


        // Check if we have a token at all
        if auth!.session == nil {
            self.statusLabel.text = ""
            return
        }
        // Check if it's still valid
        if auth!.session.isValid() && self.firstLoad {
            // It's still valid, show the player.
            print("View did load, still valid, showing player")
            self.showPlayer()
            return
        }
        // Oh noes, the token has expired, if we have a token refresh service set up, we'll call tat one.
        self.statusLabel.text = "Token expired."
        print("Does auth have refresh service? \(auth!.hasTokenRefreshService)")
        if auth!.hasTokenRefreshService {
            print("trying to renew")
            self.renewTokenAndShowPlayer()
            return
        }

        // Else, just show login dialog
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    func getAuthViewController(withURL url: URL) -> UIViewController {
        let webView = WebViewController(url: url)
        webView.delegate = self

        return UINavigationController(rootViewController: webView)
    }

    func sessionUpdatedNotification(_ notification: Notification) {
        self.statusLabel.text = ""
        let auth = SPTAuth.defaultInstance()
        self.presentedViewController?.dismiss(animated: true, completion: { _ in })
        if auth!.session != nil && auth!.session.isValid() {
            self.statusLabel.text = ""
            print("Session updated, showing player")
            self.showPlayer()
        }
        else {
            self.statusLabel.text = "Login failed."
            print("*** Failed to log in")
        }
    }

    func showPlayer() {
        self.firstLoad = false
        self.statusLabel.text = "Logged in."
        self.Information?["SpotifyUsername"] = SPTAuth.defaultInstance().session.canonicalUsername

        OperationQueue.main.addOperation {
            [weak self] in
            self?.performSegue(withIdentifier: "ShowPlayer", sender: self)
        }
        //self.performSegue(withIdentifier: "ShowPlayer", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ShowPlayer" {
            if let destination = segue.destination as? PlayController {
                destination.Information = self.Information
            }
        }
    }

    internal func productViewControllerDidFinish(_ viewController: SPTStoreViewController) {
        self.statusLabel.text = "App Store Dismissed."
        viewController.dismiss(animated: true, completion: { _ in })
    }

    func openLoginPage() {
        self.statusLabel.text = "Logging in..."
        let auth = SPTAuth.defaultInstance()
        if SPTAuth.supportsApplicationAuthentication() {
            self.open(url: auth!.spotifyAppAuthenticationURL())
        } else {
            // storyboard?.instantiateViewController(withIdentifier: <#T##String#>)
            //
            self.authViewController = self.getAuthViewController(withURL: SPTAuth.defaultInstance().spotifyWebAuthenticationURL())
            self.definesPresentationContext = true
            self.present(self.authViewController!, animated: true, completion: { _ in })
        }
    }

    func open(url: URL) {
        if #available(iOS 10, *) {
            UIApplication.shared.open(url, options: [:],
                                      completionHandler: {
                                        (success) in
                                        print("Open \(url): \(success)")
            })
        } else {
            let success = UIApplication.shared.openURL(url)
            print("Open \(url): \(success)")
        }
    }

    func renewTokenAndShowPlayer() {
        self.statusLabel.text = "Refreshing token..."
        print("trying to renew")
        SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
            SPTAuth.defaultInstance().session = session
            if error != nil {
                self.statusLabel.text = "Refreshing token failed."
                print("*** Error renewing session: \(error)")
                return
            }
            print("refreshed token")
            self.presentedViewController?.dismiss(animated: true, completion: { _ in })
            self.showPlayer()
        }
    }

    func webViewControllerDidFinish(_ controller: WebViewController) {
        // User tapped the close button. Treat as auth error
        print("UI Web view did finish")
        let auth = SPTAuth.defaultInstance()
        // Uncomment to turn off native/SSO/flip-flop login flow
        //auth.allowNativeLogin = NO;
        // Check if we have a token at all
        if auth!.session == nil {
            self.statusLabel.text = ""
            return
        }
        // Check if it's still valid
        if auth!.session.isValid() && self.firstLoad {
            // It's still valid, show the player.
            print("Still valid, showing player")
            self.showPlayer()
            return
        }
    }

    @IBAction func loginButtonWasPressed(_ sender: SPTConnectButton) {
        self.openLoginPage()
    }

    @IBAction func showSpotifyAppStoreClicked(_ sender: UIButton) {
        self.statusLabel.text = "Presenting App Store..."
        let storeVC = SPTStoreViewController(campaignToken: "your_campaign_token", store: self)
        self.present(storeVC!, animated: true, completion: { _ in })
    }

    @IBAction func clearCookiesClicked(_ sender: UIButton) {
        let storage = HTTPCookieStorage.shared
        for cookie: HTTPCookie in storage.cookies! {
            if (cookie.domain as NSString).range(of: "spotify.").length > 0 || (cookie.domain as NSString).range(of: "facebook.").length > 0 {
                storage.deleteCookie(cookie)
            }
        }
        UserDefaults.standard.synchronize()
        self.statusLabel.text! = "Cookies cleared."
    }

    @IBAction func dismissViewController () {
        self.dismiss(animated: true, completion: {})
    }
}

这是我的node.js代码:

var spotifyEndpoint = 'https://accounts.spotify.com/api/token';

/**
 * Swap endpoint
 *
 * Uses an authentication code on req.body to request access and
 * refresh tokens. Refresh token is encrypted for safe storage.
 */
app.post('/swap', function (req, res, next) {
    var formData = {
            grant_type : 'authorization_code',
            redirect_uri : clientCallback,
            code : req.body.code
        },
        options = {
            uri : url.parse(spotifyEndpoint),
            headers : {
                'Authorization' : authorizationHeader
            },
            form : formData,
            method : 'POST',
            json : true
        };

    console.log("Options" + options);
    request(options, function (error, response, body) {
        if (response.statusCode === 200) {
            body.refresh_token = encrpytion.encrypt(body.refresh_token);
        } else {
          console.log("error swapping: " + error);
        }

        res.status(response.statusCode);
        res.json(body);
    });
});

app.post('/refresh', function (req, res, next) {
    if (!req.body.refresh_token) {
        res.status(400).json({ error : 'Refresh token is missing from body' });
        return;
    }

    var refreshToken = encrpytion.decrypt(req.body.refresh_token),
        formData = {
            grant_type : 'refresh_token',
            refresh_token : refreshToken
        },
        options = {
            uri : url.parse(spotifyEndpoint),
            headers : {
                'Authorization' : authorizationHeader
            },
            form : formData,
            method : 'POST',
            json : true
        };

    request(options, function (error, response, body) {
        if (response.statusCode === 200 && !!body.refresh_token) {
            body.refresh_token = encrpytion.encrypt(body.refresh_token);
        }

        res.status(response.statusCode);
        res.json(body);
    });
});

{I}仅在我登录一次后被跳过,显示播放器,退出应用,然后再次启动应用并点击一首歌。这是为什么?

(注意,这是我从刷新令牌获得的错误:LoginViewController

我从[this]项目获得了刷新代码。 Heroku是否必要?

0 个答案:

没有答案