我正在构建一个登录页面,在提交和验证用户凭据后,它会打开一个本机移动应用程序.直到上周,我通过使用自定义方案URI实现了这个跨移动操作系统,如下所示:
function onLoginCallback() {
const redirectUri = 'customscheme:/action?param1=val1¶m2=val2';
window.location.replace(redirectUri);
}
Run Code Online (Sandbox Code Playgroud)
登录页面显示在IABT中,是In App Browser选项卡的缩写.
但是,自从Chrome 61版本发布以来,这种方法在Android上被打破了.Chrome会阻止重定向,因为没有与重定向相关的明显用户操作(有关此问题的详细信息,请参阅此处).
因此,在执行上面的代码时,我最终会在控制台中发出警告:
导航被阻止:customscheme:/ action?param1 = val1¶m2 = val2
我也尝试将自定义方案网址更新为意图网址,但无济于事.谷歌搜索这个问题并不容易提供一个明确的解决方案,所以我希望有人可以帮助我.
唉,这似乎有效.我原本预计包含jsonp调用会导致Chrome阻止最终的重定向,因为它无法将其识别为用户启动的操作.
302在Location头中返回一个自定义方案.除第一个尝试外,所有尝试都会阻止此操作.这个事实仍令人难以置信.我们正在使用AppAuth for Android应用程序来测试设置.
我正在打开端点的自定义选项卡,如下所示.代码来自这个答案.
void launchTab(Context context, Uri uri){
final CustomTabsServiceConnection connection = new CustomTabsServiceConnection() {
@Override
public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
final CustomTabsIntent intent = builder.build();
client.warmup(0L); // This …Run Code Online (Sandbox Code Playgroud) 我正在"现代化"我们的登录小部件以使用Chrome自定义标签,因为Google将在几个月内开始使用网页浏览来阻止OAuth请求.
登录小部件与我们的身份服务一起使用,该服务支持经典的"用户名和密码"登录和社交登录,通过Google/Facebook /授权代码流中的OAuth2"客户端"播放...因此Google的授权代码将传送给此身份服务,它又为我们的登录窗口小部件提供访问令牌.
访问令牌通过客户端重定向传递回移动应用程序:
window.location.replace('com.acmeusercontent.tenants.abc:\/setTokenData?accessToken='+access_token+'#');
Run Code Online (Sandbox Code Playgroud)
一切都适合经典登录:用户填写用户名和密码并提交,返回访问令牌,重定向到自定义URI方案会触发我的RedirectReceiverActivity的intent-filter.
但是,对于社交登录,重定向没有任何反应,除了Android监视器中的这一行:
I/chromium: [INFO:CONSOLE(0)] "Navigation is blocked: com.acmeusercontent.tenants.abc:/setTokenData..."
Run Code Online (Sandbox Code Playgroud)
需要明确的是:对于经典登录和社交登录,客户端重定向完全相同,但在经典登录后,允许在社交登录后被阻止!并且,如果我向窗口小部件添加一个按钮,该按钮在社交登录后执行完全相同的重定向,则只要用户单击它就可以再次允许.
这让我感到困惑: - 为什么重定向有时会被允许,有时会被阻止?- 除了要求用户在社交登录序列完成后单击按钮之外,还有什么方法可以解决这个问题吗?
我尝试了我能想到的一切:使用"intent:"语法,使用服务器端重定向模拟从代码中单击按钮,......但没有任何作用.此外,我使用Google身份验证示例研究了AppAuth库,据我所知,我做的完全相同.
因此,原生移动应用程序(Android和iOS)的标准SSO方法似乎是通过AppAuth库的OAUth2 + OpenID Connect.
这一切都很好 - 实际上似乎接近优雅.
但是,如果同一个应用程序包含需要使用相同SSO访问资源的嵌入式Web视图组件(在与所有资源需要身份验证访问的本机代码相同的Web应用程序中的同一服务器上),该怎么办?
对于初学者来说,OAuth2访问令牌(一旦获得)不会自动传播到Web应用程序中的超链接请求,对吧?那么,网页应用程序页面本身是否必须使用JavaScript进行重做以进行此类传播?移动应用程序可以重写请求来解决此问题,但是:
OAuth2不是正确的方法吗?如果是这样,那似乎是一种耻辱 - 因为AppAuth似乎对本机应用程序方面非常好.它只是将基本的Web视图浏览混合到真正混乱的图片中.
或者只有一些事实上的标准JavaScript库可以与Angular等混合使用(然后需要使用Angular等)?
我有一个iOS应用程序和一个用Spring编写的后端,并实现了OAuth2机制.
signup我的后端有一个端点,它接受一些用户数据并返回OAuth2响应,例如
{
"access_token":"9154140d-b621-4391-9fdd-fbba9e5e4188",
"token_type":"bearer",
"refresh_token":"dd612036-7cc6-4858-a30f-c548fc2a823c",
"expires_in":89,
"scope":"write"
}
Run Code Online (Sandbox Code Playgroud)
之后我想保存OIDAuthState在我的钥匙串中,所以我做了以下事情:
func saveTokenResponse(responseDict: [String: NSCopying & NSObjectProtocol]) {
let redirectURI = URL(string: kRedirectURI)
let configuration = OIDServiceConfiguration(authorizationEndpoint: URL(string: kAuthorizationEndpoint)!, tokenEndpoint: URL(string: kTokenEndpoint)!)
let request = OIDAuthorizationRequest(configuration: configuration, clientId: self.kClientID, scopes: ["write"], redirectURL: redirectURI!, responseType: OIDResponseTypeCode, additionalParameters: nil)
let accessToken = responseDict["access_token"] ?? nil
let tokenType = responseDict["token_type"] ?? nil
let refreshToken = responseDict["refresh_token"] ?? nil
let expiresIn = responseDict["expires_in"] ?? nil
let scope = responseDict["scope"] ?? nil
let …Run Code Online (Sandbox Code Playgroud) 我的应用程序与 Expo 一起使用,我import * as Google from "expo-google-app-auth";用于来自谷歌的登录用户。在开发模式下,它的工作正常。
但在独立模式下,
它重定向我以选择电子邮件,在我选择它之后将我重定向到 google.com 主页而不是返回到我的应用程序
问题:为什么将我重定向到谷歌,我该如何处理(再次 - 在开发模式下它的工作)
我的谷歌登录应用
try {
const result = await Google.logInAsync({
androidClientId: "556835760268-jm5v5u3h1bu4rcontent.com",
androidStandaloneAppClientId: "556835760268-jm5v5u3h1bu4uea3jr788tent.com",
scopes: ["profile", "email"],
});
Run Code Online (Sandbox Code Playgroud)
我的 app.json 文件:
{
"expo": {
"name": "Lior",
"slug": "Lior",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"scheme": "myapp",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"bundleIdentifier": "com.roei.liorApp",
"buildNumber": "1.0.0"
},
"web": {
"favicon": …Run Code Online (Sandbox Code Playgroud)我认为AppAuth作为一个库缺乏大量关于如何使用库本身的支持文档。有一些方法如performActionWithFreshTokens() 的记录模糊。例如,我如何使用此方法来刷新令牌。我还想知道文档是否足够清晰以供 Kotlin 解释。
让我再次想到这里的是,我如何使用这个库在 android (Kotlin) 上的以下情况下执行刷新令牌。
第一个请求令牌成功。现在假设应用程序被关闭或在后台运行一段时间,当它再次重新启动时,access_token 已过期......
此时,尝试使用此方法 createTokenRefreshRequest() 或 PerformActionWithFreshTokens() 刷新访问令牌和其他令牌需要 chrome 选项卡意图显示并要求用户再次输入用户名和密码(与对第一次)。
这是设计使然吗?有没有办法可以刷新令牌而不需要 chrome 选项卡意图显示?
使用AppAuth和OkHttp的组合是客户端。
在尝试了各种方法来实现这一目标之后,这就是我一直遇到的行为。有点困惑尝试刷新或获取新的访问令牌时是否应显示 chrome 选项卡意图。
今天我在多个iOS版本(iOS 8-11)上测试AppAuth-iOS应用程序,AppAuth-iOS在应用程序和网站之间进行SSO测试.
但是,当我在iOS 12测试版上测试相同的应用程序(在真实设备和模拟器上)时,我发现应用程序和网络之间没有SSO.SSO仅存在于iOS 12的应用之间.
我想知道以下内容:
我的设置:
截至2018年9月17日,iOS 12正式推出,问题似乎仍然存在.有人设法让这项工作?
我创建了一个 Android 应用程序,它使用 AppAuth 通过 Google OAuth 进行身份验证。在 Google Cloud Platform Console 中,我为我的应用程序创建了一个 Android OAuth 2.0 客户端 ID,并提供了应用程序包名称和签名证书指纹。一切正常。
我想验证只有我的应用程序可以使用该客户端 ID。因此,我使用不同的包名称创建了第二个应用程序,并使用不同的签名证书对其进行了签名。使用相同的客户端 ID,我仍然能够通过 Google 进行身份验证并访问 API。我认为情况不应该如此。我正在查看 AppAuth 的源代码,它看起来在身份验证流程中从未使用过应用程序签名或包名称。当然,它使用 PKCE,但我预计会发生更多事情。
因此,如果我可以轻松窃取自己的客户端 ID,那么如何阻止其他人从我的 APK 中提取我的客户端 ID 并将其用于身份验证呢?根据我的包名称,我用于重定向 URI 的自定义方案很容易找出。因此,rouge 应用程序可以将 AppAuth 配置为使用类似的重定向 URI 并捕获授权结果。而且由于 PKCE 仅用于验证来自同一位置的授权请求和代码交换,因此恶意应用程序会同时执行这两项操作,因此也没有真正的保护。
我可以将客户端 ID 类型切换为 Web 或其他,但这需要我使用客户端密钥,如果将其嵌入到应用程序中,这同样不安全。
我是否遗漏了什么,或者 Google OAuth 是否完全按照预期工作?
我正在我的 iOS 应用程序中实现应用程序身份验证库,并尝试在存档身份验证状态时清除一些警告。
'unarchiveObject(with:)' 在 iOS 12.0 中已弃用:使用 +unarchivedObjectOfClass:fromData:error: 代替
和
'archivedData(withRootObject:)' 在 iOS 12.0 中已弃用:使用 +archivedDataWithRootObject:requiringSecureCoding:error: 代替
以下工作正常,但有警告:
private func loadAuthState() {
guard let data = UserDefaults.standard.object(forKey: kAppAuthAuthStateKey) as? Data else {
return
}
if let authState = NSKeyedUnarchiver.unarchiveObject(with: data) as? OIDAuthState {
print("AuthState loaded. Access token: \(authState.lastTokenResponse?.accessToken ?? "DEFAULT_TOKEN")")
self.authState = authState
self.signedIn.update(with: .signedIn)
}
}
private func saveAuthState() {
if let authState = self.authState {
let data = NSKeyedArchiver.archivedData(withRootObject: authState)
UserDefaults.standard.set(data, forKey: kAppAuthAuthStateKey)
UserDefaults.standard.synchronize()
}
}
Run Code Online (Sandbox Code Playgroud)
更改为以下内容后,我在取消存档时崩溃(由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“不支持响应类型“(null)”。AppAuth仅支持“代码”或“代码id_token”响应类型。'): …
我遇到的问题与提出此问题的用户基本相同:Android 的 AppAuth 库缺乏适当的文档。
My problem occurs when the current access token expires, disallowing API communication from inside my app. To prevent that I forced my TokenInterceptor to acquire the token on each request from the getAccessToken method, which uses AppAuth's performActionWithFreshTokens method, that supposedly performs a token refresh request (I looked through its code). However, it always throws an AuthorizationException with error invalid_grant for me.
It crashes my app the first time, but works fine after relaunching. …
appauth ×10
android ×6
ios ×3
oauth-2.0 ×3
oauth ×2
expo ×1
google-oauth ×1
javascript ×1
kotlin ×1
react-native ×1
redirect ×1