在我正在构建的Flutter应用中,我需要针对自定义(非Google / Facebook / Twitter /等)授权服务器对用户进行身份验证。
为了实现这一目标,用户应在网页中填写其凭据。为此,可以使用WebView-plugin。但是,在用户进行身份验证后重定向页面时,应关闭WebView,并将代码传递给最初调用WebView的(Flutter)函数。
我已经完成了一些研究,我得出了以下几个选项:
是否存在解决方案,一旦打开redirect-URI,它会自动关闭浏览器(并返回验证码)?
提前致谢!
答案 0 :(得分:2)
我还没试过这个,但我的想法是使用FlutterWebviewPlugin
将用户发送到https://www.facebook.com/v2.8/dialog/oauth?client_id={app-id}&redirect_uri=fbAPP_ID://authorize
这样的网址。然后为application:openURL:options:
(在iOS上)和onNewIntent
(Android)添加原生处理程序,并修改AndroidManifest.xml
和Info.plist
以注册应用以接收来自fbAPP_ID
的网址方案。您可以使用平台频道将深层链接参数传递回Dart-land,并在Dart侧的webview上调用close()
。
答案 1 :(得分:1)
根据@Igor的要求,我将发布用于解决此问题的代码。 这个想法既基于@CollinJackson的答案,也基于AppAuth库如何做同样的事情。注意:我这里没有iOS代码,但对于经常进行iOS开发的人来说代码应该是非常简单的。
特定于Android的代码
首先,创建一个新的Activity,并在清单中注册它以接收URI:
<activity
android:name=".UriReceiverActivity"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="organization" android:host="login.oauth2" />
<!-- Triggering URI would be organization://login.oauth2 -->
</intent-filter>
</activity>
在Java代码中,默认情况下,有一个Activity(MainActivity
)。
在此活动中开始新的MethodChannel
:
public class MainActivity extends FlutterActivity implements MethodChannel.MethodCallHandler {
private static final String CHANNEL_NAME = "organization/oauth2";
public static MethodChannel channel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
channel = new MethodChannel(getFlutterView(), CHANNEL_NAME);
channel.setMethodCallHandler(this);
}
}
请注意,此代码不完整,因为我们还处理来自this
的调用。刚刚实现了这个方法,你可以添加方法调用。例如,我们使用此渠道启动Chrome自定义标签。但是,要将密钥返回Dart-land,这不是必需的(只需实现该方法)。
由于频道为public
,我们可以在UriReceiverActivity
:
public class UriReceiverActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri data = getIntent().getData();
Map<String, Object> map = new HashMap<>();
map.put("URL", data.toString());
MainActivity.channel.invokeMethod("onURL", map);
// Now that all data has been sent back to Dart-land, we should re-open the Flutter
// activity. Due to the manifest-setting of the MainActivity ("singleTop), only a single
// instance will exist, popping the old one back up and destroying the preceding
// activities on the backstack, such as the custom tab.
// Flags taken from how the AppAuth-library accomplishes the same thing
Intent mainIntent = new Intent(this, MainActivity.class);
mainIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(mainIntent);
finish();
}
}
这受到this代码的启发。
现在,重新打开Flutter应用程序,并将URL(带令牌)发送回Dart-land。
Flutter code
在Dart中,我们有一个单独的监听通道(我只会发布代码的片段,因为它不是很好并且散布在文件周围):
// Member declaration
_platform = const MethodChannel('organization/oauth2');
// Instantiation in constructor
_platform.setMethodCallHandler(_handleMessages);
// Actual message handler:
void _handleMessages(MethodCall call) {
switch (call.method) {
case "onURL":
// Do something nice using call.arguments["URL"]
}
}
在iOS上,在Android上执行相同操作,方法是使用该名称并在同一命令下向下发送URL。然后Dart代码不需要任何更改。
至于启动浏览器,我们只使用url_launcher插件。请注意,我们不限于使用WebView,我们可以使用设备上的任何浏览器。
请注意,可能有更简单的方法来实现这一点,但由于我们必须在Flutter的alpha中尽早完成,我们无法查看其他实现。我应该在某个阶段简化它,但我们还没有找到时间。