关于应用集成的身份验证协议

Hey all! My team and I have been looking into possible ways to integrate our [future] Discourse instance into our mobile application - Noom. Our iOS app is written in Objective-C with some Swift, and our Android application is written in Java with some Kotlin. We’ve been debating between full integration via API or web view as our goal is an SSO flow where our users can seamlessly transition from an in-app experience to our Discourse instance.

I’m currently waiting on our QA team to get back to me on which authentication protocols we currently use, but I was curious as to anyone else’s experience integrating Discourse into a mobile application with or without SSO, and what methods (if any) you found most useful throughout the process. I’m aware of Discourse’s compatibility with OAuth/2, although not aware of other potential protocols.

My apologies if this is in the wrong category!

1 个赞

There is a new way of authentication. However the documentation is yet to be released.

3 个赞

I’m going to update the documentation about delegated authentication soon, but I can give you some pointers right here.

First you need to open a browser session to discourse.site/user-api-key/new with the following parameters:

scopes: 'notifications,session_info,one_time_password',
client_id: YOUR_APP_CLIENT_ID,
nonce: GENERATED_NONCE,
auth_redirect: YOUR_APP_URL_SCHEME,
application_name: YOUR_APP_NAME,
push_url: PUSH_URL (if you are going to send PNs from Discourse to your app),
public_key: PUBLIC_KEY (generated in your app)

You can have a look at the implementation of our DiscourseMobile app for details on the above but the main idea is that your app will launch a browser screen to the URL above, asking the user to authenticate to the Discourse site and authorize your app access to it. Once user authorizes access, Discourse will redirect to YOUR_APP_URL_SCHEME?payload= with an encrypted payload. You’ll need to set up your app to decrypt the payload and store the authToken. In iOS, you should use ASWebAuthenticationSession | Apple Developer Documentation (I don’t know if there is an Android equivalent).

Your authToken can make API requests limited by the scopes requested initially, for a full list of scopes, please look under allow user api key scopes in site settings.

The one_time_password scope allows the authToken to make a request for a one-time-password. The endpoint for this is /user-api-key/otp with the parameters auth_redirect, application_name and public_key.

I will write a proper documentation shortly, but this should help you get started.

5 个赞

@hosna + @pmusaraj Thank you both! I will pass this information along to our QA director.

1 个赞

@pmusaraj 你好,目前是否有面向公众的官方文档?我想深入了解一下。

我打算在接下来的几天里着手解决这个问题,我会更新我的成功或失败情况。如果任何人有任何指南或建议,我将不胜感激 :slight_smile:

我想您正在寻找 https://meta.discourse.org/t/user-api-keys-specification/48536,特别是“API 密钥生成流程”这一节。

1 个赞

嘿,Penar,感谢你的指导。我在这方面远非专家,以前没怎么接触过加密或这类 API,所以想请教一下如何对这些参数进行编码?我正在查看你的 DiscourseMobile 应用,但我从未使用过 JavaScript,因此遇到了一些困难。

nonce 和 client_id——它们是否只是随机生成的 16 字节和 32 字节字符串,并进行十六进制编码?
public_key——关于如何生成它有什么建议吗?我尝试使用 此处资源,这会得到一个 SecKeyRef。我是否需要将其转换为 NSData,然后再进行 UTF-8 编码?

你碰巧有 Swift 或 Objective-C 的代码片段吗?我会自己搞定,但这对我来说全是新东西,所以任何一点帮助都非常感激。

nonce 是一个随机密钥,请参见此处 generateNonceDiscourseMobile/js/site_manager.js at main · discourse/DiscourseMobile · GitHub

client_id 是应用的 deviceToken,它通过 GitHub - react-native-push-notification/ios: React Native Push Notification API for iOS. · GitHub 传递给应用。
public_key 由 GitHub - SamSaffron/react-native-key-pair · GitHub 生成,该库非常小,相关部分是用 Objective C 编写的。

4 个赞

嘿,Penar,谢谢你的链接,非常有用。
我正在取得进展,但我认为我的公钥格式不正确,这个格式看起来怎么样?

https://myserver.com/user-api-key/new?client_id=11223344556677889900AABBCCDDEEFF11223344556677889900AABBCCDDEEFF&nonce=11223344556677889900AABBCCDDEEFF&application_name=AppName&public_key=-----BEGIN%20PUBLIC%20KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtoNwaYpbUcX1vqxPkxRA%0D1EyfLPxkKL6zgx4Fkk9zkYbTPTWQFuqy+O1EJtVnsW+Tx8iarFLI+ypghcx22nI0%0DN/hDFYsaT/xri+LLDc790uf2UtyolgBJfkyjJDxIXXy0pdpi6f2dgKMN2holDkxf%0DTUUnZad+wE8gT8IciX1XjU97MOngSV+IDeKPLomTuTiI1Z0hJe4WDww5+53ci4o4%0DoE5A79H/Fz/QY8vDLTcBNrQ6OdJYsRqhE5M+1sNmxpqDKT+9NcAPY7yphxm1iLuV%0Dm7c6K/xrbZExGDQd1qHvggT2ldMJIsmQEnleMdfuaYLh8+EYt8LNQ8X86V0Jj+9C%0DmQIDAQAB-----END%20PUBLIC%20KEY-----&auth_redirect=appname://auth&scopes=notifications,session_info,one_time_password

在日志控制台中我看到:
OpenSSL::PKey::RSAError (Neither PUB key nor PRIV key: nested asn1 error) /var/www/discourse/app/controllers/user_api_keys_controller.rb:189:in `initialize’

谢谢

我刚刚发布了一个脚本来完成这个确切的功能 @xceph

请查看 为测试生成用户 API 密钥

3 个赞

谢谢!我刚刚取得了进展,我的问题出在参数的编码上。我使用了 iOS 的 URLQueryAllowedCharacterSet,它不会编码 “/” 或 “+”。一旦我创建了一个测试 Ruby 脚本来隔离导致崩溃的那行代码,我就能逆向推导并解决问题了。谢谢!

2 个赞

似乎无法让重定向正常工作,我使用了 Penar 建议的 ASWebAuthenticationSession。调用看起来按预期运行,我收到了“授权”对话框,点击后进入一个纯白屏幕,我猜这是尝试进行重定向,但它没有关闭并将信息发送给我的回调。我已经测试过,我的自定义 URL 在 Safari 中工作正常。此外,如果移除 auth_redirect,我会看到“我们刚刚生成了一个新的用户 API 密钥供使用……

纯白屏幕很可能表明服务器遇到了错误。当你再次尝试时,请检查你的 Discourse 站点的 /logs,那里可能有一些相关信息。你可能遇到了同一个客户端 ID 无法多次注册的问题。可能需要手动清除 Discourse 实例中的该客户端 ID,目前只能通过 Rails 控制台完成。

2 个赞

是的,这确实来自管理员面板中的“允许用户 API 认证重定向”设置。需要配置该选项后,问题就解决了。

目前我可以完成认证,但在 iOS 上解码 payload 时遇到了困难。我可以用接收到的 payload 和我的私钥在 Ruby 或 NodeJS 中解码,以证明流程是可行的,但让 iOS 直接解码比我预想的要棘手得多。

1 个赞

如果您查看我们应用的源代码,其中包含了解码方法的示例。要让所有功能正常运行,所需的代码量相当复杂。

4 个赞

谢谢,我已经让所有功能都正常运行了。稍后我会发布一些代码片段,帮助其他希望在 iOS 上原生实现此功能的人。感谢指导。

以这种方式创建 API 令牌后,能否用它来在 WebView 中认证登录?我原本以为应用就是这么做的,但我目前还在研究这部分。目标是提供 API 访问权限,同时允许用户通过正常的网页客户端 Reface 进行浏览,两者共用一个登录凭证。

1 个赞