Request authorization called by POST method to Last.fm API using swift.

huangapple go评论69阅读模式
英文:

Request authorization called by POST method to Last.fm API using swift

问题

I'm trying to follow Last.fm's tutorial to consume their API in an iOS app (using Swift), but I don't know what's wrong with my code. They ask to do something called Last.fm method signature which I'm not understanding how to insert into my program. Here is the link to the tutorial I try to follow: https://www.last.fm/api/mobileauth

Here is my current code:

import UIKit

struct LoginRequestBody: Codable { 
    var username: String 
    var password: String 
    var api_key: String 
    var api_sig: String 
}

enum AuthenticationError: Error { 
    case invalidCredentials 
    case custom(errorMessage: String) 
}

class APIService {
    func requestAPI(username: String, password: String, api_key: String, api_sig: String) {
        guard let url = URL(string: "http://www.last.fm/api/auth/?api_key=xxx") else {
            return
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"
        
        let body = LoginRequestBody(username: username, password: password, api_key: api_key, api_sig: api_sig)
        let bodyStr = [
            "username": "\(body.username)",
            "password": "\(body.password)",
            "api_key": "\(body.api_key)",
            "api_sig": "\(body.api_sig)"]
        
        urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: bodyStr, options: .fragmentsAllowed)
        
        let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
            guard let data = data, error == nil else {
                return
            }
            
            do {
                let response = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
                print(response)
            } catch {
                print(error)
            }
        }
        task.resume()
    }
}
英文:

I'm trying to follow Last.fm's tutorial to consume their API in an iOS app (using Swift), but I don't know what's wrong with my code. They ask to do something called Last.fm method signature which I'm not understanding how to insert into my program. Here is the link to the tutorial I try to follow: https://www.last.fm/api/mobileauth

Here is my current code:

import UIKit

struct LoginRequestBody: Codable { 
    var username: String 
    var password: String 
    var api_key: String 
    var api_sig: String 
}

enum AuthenticationError: Error { 
    case invalidCredentials 
    case custom(errorMessage: String) 
}

class APIService {
    func requestAPI(username: String, password: String, api_key: String, api_sig: String) {
        guard let url = URL(string: "http://www.last.fm/api/auth/?api_key=xxx") else {
            return
        }
        
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = "POST"
        
        let body = LoginRequestBody(username: username, password: password, api_key: api_key, api_sig: api_sig)
        let bodyStr = [
            "username": "\(body.username)",
            "password": "\(body.password)",
            "api_key": "\(body.api_key)",
            "api_sig": "\(body.api_sig)"]
        
        urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: bodyStr, options: .fragmentsAllowed)
        
        let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
            guard let data = data, error == nil else {
                return
            }
            
            do {
                let response = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
                print(response)
            } catch {
                print(error)
            }
        }
        task.resume()
    }
}

答案1

得分: 1

你遇到了你在评论中提到的错误,这是因为你尝试使用http而不是https来连接端点,而苹果应用传输安全性机制阻止了这样做。

你有两个选择(也许更多 :))

  1. 看看Last.fm是否支持https,如果支持,那就使用它
  2. 允许你的应用程序使用http。你可以通过将以下内容添加到你的info.plist来实现:
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

不过,在这样做之前,请参考这个很好的答案,它描述了在使用http而不是https时所面临的所有风险。

英文:

You are seeing the error you mentioned in your comments because you try to connect to an endpoint using http instead of https and Apples App Transport Security mechanism blocks you from doing that.

You have two options (maybe more :))

  1. See if Last.fm supports https instead and if they to, then use that
  2. Allow your app to use http instead. You do so by adding this to your info.plist
&lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;NSAllowsArbitraryLoads&lt;/key&gt;
    &lt;true/&gt;
&lt;/dict&gt;

Before you do so though, please see also this great answer describing all the risks you take if you use http over https

答案2

得分: 0

你应该确保使用 安全https://ws.audioscrobbler.com/2.0/auth.getMobileSession 终端,就像文档中提到的那样。这很重要,因为你会通过网络传送用户的敏感数据,比如用户的密码。

接下来,你应该生成你的 POST 请求的主体。

如果你在生成签名时遇到困难,下面是方法:

  1. 按字母顺序排列你请求的所有参数(即键-值对)和终端方法,例如:
    • api_key -&gt; your_key
    • method -&gt; auth.getMobileSession
    • password -&gt; somebodys_password
    • username -&gt; somebody
  2. 将它们连接成一个字符串,格式为 key1value1key2...keyNvalueN,例如:
    • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebody
  3. 将你的 API 密钥(假设它的值为 apisecret)追加到该字符串中(只追加 apisecret 这个值):
    • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebodyapisecret
    • 你在注册你的应用程序时获得了该 API 密钥,以及你的 API 密钥
  4. 生成该字符串的 MD5 散列值:
    • 不确定在 Swift 中如何完成此操作,但 Google 和 Stackoverflow 是你的朋友
    • 确保你已经正确地将所有字符串进行了 UTF-8 编码
  5. 这个散列就是你将作为 api_sig 发送的签名,包含在你的请求中。

这也是为其他 API 调用生成签名的方式。

注意:当你使用 getMobileSession 方法时,你不会将用户重定向到一个 last.fm 页面,用户可以在该页面上允许你的应用程序访问他们的个人资料。相反,你直接将用户的凭据发送到 last.fm 进行身份验证。

注意:对于我而言,这样的 HTTP POST 请求的主体是这样组装的:key1=value1&amp;key2=value2&amp;... 或许 Swift 已经在内部完成了这个过程。

英文:

You should definitely use the secure https://ws.audioscrobbler.com/2.0/auth.getMobileSession endpoint like it is mentioned in the documentation. That is also important because you send sensitive data over the wire like the user's password.

Next you should generate the body of your POST request.

If you struggle to generate the signature, here's how:

  1. Order all parameters (i.e. key-value pairs) of your request and the endpoint method alphabetically, e.g.
    • api_key -&gt; your_key
    • method -&gt; auth.getMobileSession
    • password -&gt; somebodys_password
    • username -&gt; somebody
  2. Concatenate them to one string like the schema key1value1key2...keyNvalueN, e.g.
    • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebody
  3. Append your API secret (let's assume it has the value apisecret) to that string (and only that value apisecret)
    • api_keyyour_keymethodauth.getMobileSessionpassword...usernamesomebodyapisecret
    • You've got that API secret when you registered your App at last.fm, along with your API key
  4. Generate the MD5 hash of that string
    • not sure how this would be done in Swift but Google and Stackoverflow are your friends
    • be sure your have correctly UTF-8 encoded all the strings
  5. This hash is the signature you will send as api_sig in your request

This is also the way to generate the signature for other API calls.

Note: when you use the getMobileSession approach you won't redirect the user to a last.fm page where they could allow your app to access their profile. Instead you are sending directly the user's credentials to last.fm to authenticate.

Note: for me the body of such a HTTP POST request was assembled like key1=value1&amp;key2=value2&amp;... maybe Swift is doing this internally already.

huangapple
  • 本文由 发表于 2023年5月21日 23:23:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300623.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定