Swift 中的 Steam OpenID 身份验证:仅通过所有其他尝试

发布于 2025-01-17 19:00:09 字数 3640 浏览 5 评论 0原文

解决方案

正如下面的用户所述,我必须对 nonce 和 sig URL 元素中的 + (%2B) 符号进行转义/编码。首先,我将这两个元素编辑为 URLComponent 对象。在这种情况下,以下到 URL 对象的转换将再次单独替换 sig 中的 %,使其成为 %252B

我通过将 URL 转换为纯字符串、对其进行编辑并将其转换回 URL 来解决该问题,而不是编辑 URLComponent 元素。


我正在使用 Swift 开发一个应用程序来配合我正在进行的项目。我们希望通过 Steam OpenID 处理登录过程。在网站上(用 Angular 构建)它运行完美,但我在应用程序部分遇到了一些麻烦。

这是我的问题:

我们的后端不会在每次尝试时都为我提供令牌。

当它通过和失败时,它似乎是相当随机的,但总的来说,它是关于所有其他尝试的。

我怀疑是我们后端的 OpenID 库出了问题,所以我自己在 Steam 的端点上进行了多次尝试,但行为完全相同。

这是我的代码:

这是在登录按钮点击时调用的:

var session: ASWebAuthenticationSession?

func signIn() {
    
    let scheme = "myauth"
    
    let authUrl = URL(string: "https://steamcommunity.com/openid/login
        ?openid.ns=http://specs.openid.net/auth/2.0
        &openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select
        &openid.identity=http://specs.openid.net/auth/2.0/identifier_select
        &openid.return_to=https://mywebsite.com/appauth
        &openid.realm=https://mywebsite.com
        &openid.mode=checkid_setup")!
    
    self.session = ASWebAuthenticationSession.init(url: authUrl, callbackURLScheme: scheme, completionHandler: { callbackURL, error in
        guard error == nil, let successURL = callbackURL else {
            print("Error: ASWebAuthSession returned with: \(error!)")
            return
        }
        var queryItems = URLComponents(string: successURL.absoluteString)!.queryItems!
        
        HttpService.getSteamResponse(queryItems: queryItems)
    })
    
    session?.presentationContextProvider = self
    session?.prefersEphemeralWebBrowserSession = true
    self.session?.start()
}

这是引用的函数:

static func getSteamResponse(queryItems: [URLQueryItem]) {
    
    var mutatedItems = queryItems
    if var item = queryItems.enumerated().first(where: {$0.element.name == "openid.mode"}) {
        item.element.value = "check_authentication"
        mutatedItems[item.offset] = item.element
    } else {
       print("Error: Steam check has no item 'openid.mode'")
    }
    
    var urlComps = URLComponents(string: "https://steamcommunity.com/openid/login")!
    urlComps.queryItems = mutatedItems
    let url = urlComps.url!
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        
        guard let data = data else {
            debugPrint("Error: Steam check responded with: \(String(describing: error))")
            return
        }
        
        if let httpResponse = response as? HTTPURLResponse{
            print("Info: Steam check responsed with: \(httpResponse.statusCode)")
        }
        
        print("Info: Steam check data: \(String(decoding: data, as: UTF8.self))")
    }.resume()
}

这​​包括一些可能没有必要的额外检查,并且在某些方面可能不是非常优化(我是仍在学习 Swift),但总而言之,它应该可以工作(并且确实......有时)

更多信息:

请注意,我用占位符替换了我们项目的实际链接。

据我了解,ASWebAuthenticationSession 回调只需要一个 URL 方案,我将其替换为 myauth。由于我注意到 Steam(或一般的 OpenID?)不喜欢自定义 URL 方案,因此我使用 https://mywebsite.com/appauth,它使用 301 重定向到类似 myauth:/ 的内容。 /foobar.com 包含所有参数,因此我可以在应用程序中接收它们(我想这也可以通过通用链接工作,但我还没有付费开发帐户)。

现在,当我运行这段代码时,我无法得到一致的响应。它始终是带有 ns:http://specs.openid.net/auth/2.0200 和看似随机的 is_valid:falseis_valid:true

我运行了多次,尝试在中间重新部署应用程序,甚至删除模拟器设备,但我无法获得一致的结果。

不幸的是,我只能尝试这么多次,因为在大约 15 次登录后,Steam 将阻止我的网络登录。

在我上次的试验中,我收到了假,假,真,假,真

我的猜测是存在一些我无法注意到的并发问题。

我感谢有关此主题的任何帮助!

Solution:

As a user below stated, I had to escape/encode the + (%2B) symbol in the nonce and sig URL elements. First I edited both elements as the URLComponent object. In that case, the following conversion to a URL object would replace the % in the sig by itself again, making it %252B.

I resolved that problem by converting the URL to a plain string, editing that and converting it back to a URL, rather than editing the URLComponent elements.


I'm working on an app with Swift to accompany a project I'm on. We want to handle the login process via Steam OpenID. On the website (built with Angular) it works flawlessly, but I'm having some troubles on the app part.

This is my problem:

Our backend doesn't provide me a token on every attempt.

It seems to be rather random when it passes and when it fails, but in total it's been about every other attempt.

I suspected the OpenID library in our backend to be the fault, so I did multiple tries on Steam's endpoint by myself, but the behavior is exactly the same.

This is my code:

This is called on login button tap:

var session: ASWebAuthenticationSession?

func signIn() {
    
    let scheme = "myauth"
    
    let authUrl = URL(string: "https://steamcommunity.com/openid/login
        ?openid.ns=http://specs.openid.net/auth/2.0
        &openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select
        &openid.identity=http://specs.openid.net/auth/2.0/identifier_select
        &openid.return_to=https://mywebsite.com/appauth
        &openid.realm=https://mywebsite.com
        &openid.mode=checkid_setup")!
    
    self.session = ASWebAuthenticationSession.init(url: authUrl, callbackURLScheme: scheme, completionHandler: { callbackURL, error in
        guard error == nil, let successURL = callbackURL else {
            print("Error: ASWebAuthSession returned with: \(error!)")
            return
        }
        var queryItems = URLComponents(string: successURL.absoluteString)!.queryItems!
        
        HttpService.getSteamResponse(queryItems: queryItems)
    })
    
    session?.presentationContextProvider = self
    session?.prefersEphemeralWebBrowserSession = true
    self.session?.start()
}

This is the referenced function:

static func getSteamResponse(queryItems: [URLQueryItem]) {
    
    var mutatedItems = queryItems
    if var item = queryItems.enumerated().first(where: {$0.element.name == "openid.mode"}) {
        item.element.value = "check_authentication"
        mutatedItems[item.offset] = item.element
    } else {
       print("Error: Steam check has no item 'openid.mode'")
    }
    
    var urlComps = URLComponents(string: "https://steamcommunity.com/openid/login")!
    urlComps.queryItems = mutatedItems
    let url = urlComps.url!
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        
        guard let data = data else {
            debugPrint("Error: Steam check responded with: \(String(describing: error))")
            return
        }
        
        if let httpResponse = response as? HTTPURLResponse{
            print("Info: Steam check responsed with: \(httpResponse.statusCode)")
        }
        
        print("Info: Steam check data: \(String(decoding: data, as: UTF8.self))")
    }.resume()
}

This includes some additional check that might not be necessary and it might not be very optimized at some points (I'm still learning Swift), but all in all it should be working (and does... sometimes)

Further information:

Note that I replaced the actual links to our project with placeholders.

As I understand it, the ASWebAuthenticationSession callback does only need an URL scheme, which I replaced with myauth. Since I noticed Steam (or OpenID in general?) not liking custom URL schemes, I instead use https://mywebsite.com/appauth, which redirects with 301 to something like myauth://foobar.com with all parameters, so I can receive them in the app (I guess this would work via Universal links as well, but I don't have a paid dev account yet).

Now when I run this code, I can't get a consistent response. It's always a 200 with ns:http://specs.openid.net/auth/2.0 and seemingly random is_valid:false or is_valid:true.

I ran this multiple times, tried redeploying the app in-between and even erasing the simulator device, but I can't get consistent results.

Unfortunately I can only try so many times, because Steam will block the login from my network after about 15 logins.

On my last trial I received false, false, true, false, true.

My guess would be there to be some issues with concurrency that I can't notice.

I appreciate any help on this topic!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葬﹪忆之殇 2025-01-24 19:00:09

我在Golang中也遇到了同样的事情。结果发现,我没有对nonce和sig字符串进行转义,而是在请求中的GET参数中修改了它

I encountered the same thing in Golang. Turned out, I didn't escape the nonce and sig string, and it was modified in GET parameter in the request

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文