質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

Q&A

1回答

3592閲覧

flutterでflutter_appauthプラグインを使ってoauthログインを実装したい3

sagme

総合スコア10

Flutter

Flutterは、iOSとAndroidのアプリを同じコードで開発するためのフレームワークです。オープンソースで開発言語はDart。双方のプラットフォームにおける高度な実行パフォーマンスと開発効率を提供することを目的としています。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Dart

Dartは、Googleによって開発されたJavaScriptの代替となることを目的に作られた、ウェブ向けのプログラミング言語である。

0グッド

0クリップ

投稿2020/04/07 08:29

編集2020/04/07 13:09

前提・実現したいこと

前回の質問 flutterでflutter_appauthプラグインを使ってoauthログインを実装したい2 からの続きの質問です。

アプリから、認証サーバのログインページを呼び出してログインし、認証が済んだら
アプリに戻ってアクセストークンでAPIを取得しようとしています。

認証サーバは自前で用意したものを使います。(FirebaseやSNS認証などは使わない)
今回はKeycloakを使い、DockerのコンテナでローカルPCに立ち上げています。
そのため、以下のプラグインを使用して実装しようとしています。

flutter_appauth 0.8.2

こちらのGitHubのサンプルコードを参照して実装しました。
MaikuB/flutter_appauth

発生している問題・エラーメッセージ

困っていることその①
アプリから、認証サーバのログインページを呼び出してログインし、認証済みになるところまでは動作するのですが
callback画面からアプリに制御が戻らず、エラーになっています。

① アプリ初期画面
イメージ説明

② 認証サーバのログイン画面
イメージ説明

③ ログイン画面にユーザID,PWを入力
イメージ説明

④ 認証成功した後のcallback画面(戻るリンクは機能していない)
イメージ説明

⑤ ↑の画面の×印をタップして画面を閉じてアプリに戻った所
イメージ説明

⑥エラーメッセージ(④の画面を手動で閉じたので、ソースコード中のresultに何も入らずエラーになった
エラー後もアプリは動いているが、その後の画面遷移はしていない
イメージ説明

Launching lib/main.dart on Android SDK built for x86 64 in debug mode... ✓ Built build/app/outputs/apk/debug/app-debug.apk. I/flutter ( 5095): 1 I/flutter ( 5095): 2 I/flutter ( 5095): e=PlatformException(authorize_and_exchange_code_failed, Failed to authorize: [error: null, description: User cancelled flow], null)

該当のソースコード

dart

1main.dart 2 3import 'package:flutter/material.dart'; 4import 'package:http/http.dart' as http; 5import 'package:flutter_appauth/flutter_appauth.dart'; 6import 'package:flutter_auth_login_app/screen1.dart'; 7 8void main() => runApp(MyApp()); 9 10class MyApp extends StatelessWidget { 11 12 Widget build(BuildContext context) { 13 return MaterialApp( 14 title: 'Flutter Demo', 15 theme: ThemeData( 16 primarySwatch: Colors.blue, 17 ), 18 home: MyHomePage(title: 'Flutter Demo Home Page'), 19 ); 20 } 21} 22 23class MyHomePage extends StatefulWidget { 24 MyHomePage({Key key, this.title}) : super(key: key); 25 final String title; 26 27 _MyHomePageState createState() => _MyHomePageState(); 28} 29 30class _MyHomePageState extends State<MyHomePage> { 31 final String _clientId = 'test001'; 32 final String _redirectUrl = 'http://10.0.2.2:10081/…/callback.php' ; // callbackのURL 33 34 final List<String> _scopes = <String>[ 35 'openid', 36 'offline_access', 37 ]; 38 39// String _codeVerifier; 40// String _authorizationCode; 41 String _accessToken; 42 String _refreshToken; 43 String _userInfo = ''; 44 45 final FlutterAppAuth _appAuth = FlutterAppAuth(); 46// final TextEditingController _authorizationCodeTextController = TextEditingController(); 47 final TextEditingController _idTokenTextController = TextEditingController(); 48 final TextEditingController _accessTokenExpirationTextController = TextEditingController(); 49 final TextEditingController _accessTokenTextController = TextEditingController(); 50 final TextEditingController _refreshTokenTextController = TextEditingController(); 51 52 final AuthorizationServiceConfiguration _serviceConfiguration = 53 AuthorizationServiceConfiguration( 54 'http://10.0.2.2:18080/…/auth', // 認証エンドポイントのURL 55 'http://10.0.2.2:18080/…/token' // トークンエンドポイントURL 56 ); 57 58 59 void initState() { 60 super.initState(); 61 } 62 63 void _loginFunc() async { 64 // 認証とアクセス、ID、リフレッシュトークン取得を一度にやる場合 65 print('1'); 66 try { 67 print('2'); // ここまで流れて↓のresultに値が戻らないため、エラーになる 68 final AuthorizationTokenResponse result = 69 await _appAuth.authorizeAndExchangeCode( 70 AuthorizationTokenRequest( 71 _clientId, 72 _redirectUrl, 73 serviceConfiguration: _serviceConfiguration, 74 scopes: _scopes), 75 ); 76 77 print('3'); 78 // アクセス、ID、リフレッシュトークン格納 79 if (result != null) { 80 _accessToken = _accessTokenTextController.text = result.accessToken; 81 _idTokenTextController.text = result.idToken; 82 _refreshToken = _refreshTokenTextController.text = result.refreshToken; 83 _accessTokenExpirationTextController.text = result.accessTokenExpirationDateTime?.toIso8601String(); 84 } 85 86 // API取得 87 print('4=$result'); 88 if (result != null) { 89 print('4 in'); 90 await _testApi(result); 91 } 92 93 // 画面遷移 94 print('5'); 95 _gotoScreen1(); 96 97 // エラー処理 98 } catch(e) { 99 print('e=$e'); //エラー時のメッセージ出力 100 } 101 } 102 103 // API取得 104 Future<void> _testApi(TokenResponse response) async { 105 final http.Response httpResponse = await http.get( 106 'http://10.0.2.2:18082/…/data', // APIのエンドポイント 107 headers: <String, String>{'Authorization': 'Bearer $_accessToken'}); 108 setState(() { 109 _userInfo = httpResponse.statusCode == 200 ? httpResponse.body : ''; 110 }); 111 } 112 113 // 画面遷移 screen1 API取得後に遷移する画面 114 void _gotoScreen1() { 115 Navigator.pushReplacement( 116 context, 117 new MaterialPageRoute<Null>( 118 settings: const RouteSettings(name: "/screen1"), 119 builder: (BuildContext context) => Screen1(api:_userInfo), 120 ), 121 ); 122 } 123 124 // widget 125 126 Widget build(BuildContext context) { 127 128 return Scaffold( 129 appBar: AppBar(title: Text(widget.title),), 130 body: Center( 131 132 child: Column( 133 mainAxisAlignment: MainAxisAlignment.center, 134 children: <Widget>[ 135 136 Padding( 137 padding: EdgeInsets.only(bottom: 40), 138 child: Text('アプリ初期画面'), 139 ), 140 141 FlatButton(key:null, onPressed: _loginFunc, 142 shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3.0)), 143 color: Color(0xFF4c6cb3), // 群青色 144 child: Text('ログインページへ',), 145 ) 146 ], 147 ), 148 ), 149 ); 150 } 151} 152 153

dart

1screen1.dart 2 3import 'package:flutter/material.dart'; 4import 'package:http/http.dart' as http; 5import 'package:flutter_appauth/flutter_appauth.dart'; 6 7//// widget //// 8class Screen1 extends StatefulWidget { 9 String api; 10 11 Screen1({Key key, this.api}): super(key: key); 12 13 14 _Screen1State createState() => _Screen1State(this.api); 15} 16 17class _Screen1State extends State<Screen1> { 18 String _api; 19 20 _Screen1State(String api){ 21 this._api = api; 22 } 23 24 25 void initState() { 26 super.initState(); 27 } 28 29 30 Widget build(BuildContext context) { 31 32 return Scaffold( 33 resizeToAvoidBottomInset: false, 34 appBar: AppBar(title: Text('screen1'),), 35 body: Column( 36 children: [ 37 Text('screen1'), 38 Text('$_api'), 39 ] 40 ) 41 ); 42 } 43}

php

1callback.php 2 3 // webアプリの名残でphpファイルに書いてあるが、php部分は無し。戻るリンクの中身は無い。 4 認証成功<br> 5 <a href="">戻る</a> 6

試したこと

なぜ引数を渡してもresultが返ってこないのかを調べるため
_loginFunc()の認証する部分↓の中で

final AuthorizationTokenResponse result = await _appAuth.authorizeAndExchangeCode( AuthorizationTokenRequest( _clientId, // php-test _redirectUrl, serviceConfiguration: _serviceConfiguration, scopes: _scopes), );

何が行われているのか確認しようとしましたが、どうやって確認したら良いか分からない状態です。

困っていることその②

参照したGitのサンプルコード MaikuB/flutter_appauth の中には、flutter_appauth だけでなく
flutter_appauth_platform_interfaceの実装も含まれていましたが、この部分がどういう役割をしているのか、flutter_appauth の main.dart からどのように参照されて使われているのかが分かりません。

そのため、自分の書いた上記のコードにはflutter_appauth_platform_interfaceの実装が含まれていないので
これが原因なのかなと思いますが、使い方が分からず困っています。

補足情報(FW/ツールのバージョンなど)

macOS Mojave
Flutter 1.12.13+hotfix.5
Tools • Dart 2.7.0

説明が長くなってしまいましたが、どうぞよろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

追記:
解決はしていないのですが、色々試したところ現象が変化し
困っている内容が変わったため、こちらの質問を一旦クローズし、新たに質問を立て直させて頂きます

○現在の状況
困っていることその①について
認証後にアプリに戻ってこない → 戻ってくるようにはなったが、直後にアプリが落ちる(改めて別の質問を立てます)。
アプリに戻ってくる部分の解決方法は、前の質問
flutterでflutter_appauthプラグインを使ってoauthログインを実装したい2 の自己解決の追記に書きました。

困っていることその②
サンプルコードのflutter_appauth_platform_interfaceの実装がなぜあるのか分からない。
flutter_appauth_platform_interfaceは、flutter_appauthから更に呼ばれているプラグインなので
実装部分は書かなくても動く(自分のアプリはそう)のではないかと思うのですが
なぜこのサンプルコードに実装部分が含まれているのかが分からない。

まだ分からない部分について、解決方法ご存知の方がいれば、引き続きご意見をお待ちしています。

投稿2020/04/14 06:27

sagme

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問