添加 github oAuth 认证,添加错误提醒

This commit is contained in:
yifeng.yl
2019-05-29 18:46:12 +08:00
parent 9e7cd804e5
commit dbcdbab7d2
13 changed files with 197 additions and 67 deletions

View File

@ -14,6 +14,7 @@
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="io.flutter.app.FlutterApplication"
android:label="fluttergo" android:label="fluttergo"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher_logo"> android:icon="@mipmap/ic_launcher_logo">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

BIN
assets/images/gitHub.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,10 +1,14 @@
class Api{ class Api{
// static const String BASE_URL = 'http://127.0.0.1:6001/'; static const String BASE_URL = 'http://30.10.29.190:6001/';
static const String BASE_URL = 'http://flutter-go.alibaba.net/'; // static const String BASE_URL = 'http://flutter-go.alibaba.net/';
static const String DO_LOGIN = BASE_URL+'doLogin';//登陆 static const String DO_LOGIN = BASE_URL+'doLogin';//登陆
static const String CHECK_LOGIN = BASE_URL+'checkLogin';//验证登陆 static const String CHECK_LOGIN = BASE_URL+'checkLogin';//验证登陆
static const String LOGOUT = BASE_URL+'logout';//退出登陆 static const String LOGOUT = BASE_URL+'logout';//退出登陆
static const String GET_USER_INFO = BASE_URL+'getUserInfo';//获取用户信息
static const String RedirectIp = 'http://100.81.211.172/';
} }

View File

@ -93,6 +93,7 @@ class _WidgetDemoState extends State<WidgetDemo> {
ApplicationEvent.event ApplicationEvent.event
.fire(CollectionEvent(widget.title, _router, true)); .fire(CollectionEvent(widget.title, _router, true));
} }
return; return;
} }
print('删除错误'); print('删除错误');

View File

@ -2,4 +2,4 @@ import 'package:event_bus/event_bus.dart';
class ApplicationEvent{ class ApplicationEvent{
static EventBus event; static EventBus event;
} }

View File

@ -4,4 +4,10 @@ class CollectionEvent{
final bool isRemove; final bool isRemove;
// token uid... // token uid...
CollectionEvent(this.widgetName,this.router,this.isRemove); CollectionEvent(this.widgetName,this.router,this.isRemove);
}
class UserGithubOAuthEvent{
final String loginName;
final bool isSuccess;
UserGithubOAuthEvent(this.loginName,this.isSuccess);
} }

View File

@ -4,27 +4,39 @@ import './net_utils.dart';
import '../model/user_info.dart'; import '../model/user_info.dart';
import 'package:flutter_go/api/api.dart'; import 'package:flutter_go/api/api.dart';
class DataUtils {
class DataUtils{
// 登陆获取用户信息 // 登陆获取用户信息
static Future<UserInfo> doLogin(Map<String,String> params) async{ static Future doLogin(Map<String, String> params) async {
var response = await NetUtils.post(Api.DO_LOGIN, params); var response = await NetUtils.post(Api.DO_LOGIN, params);
print(response);
try {
UserInfo userInfo = UserInfo.fromJson(response['data']);
return userInfo;
} catch (err) {
return response['data'];
}
}
// 获取用户信息
static Future<UserInfo> getUserInfo(Map<String, String> params) async {
var response = await NetUtils.get(Api.GET_USER_INFO, params);
print(response);
UserInfo userInfo = UserInfo.fromJson(response['data']); UserInfo userInfo = UserInfo.fromJson(response['data']);
return userInfo; return userInfo;
} }
// 验证登陆 // 验证登陆
static Future<bool> checkLogin() async{ static Future<bool> checkLogin() async {
var response = await NetUtils.get(Api.CHECK_LOGIN); var response = await NetUtils.get(Api.CHECK_LOGIN);
print('验证登陆:$response'); print('验证登陆:$response');
return response['success']; return response['success'];
} }
// 退出登陆 // 退出登陆
static Future<bool> logout() async{ static Future<bool> logout() async {
var response = await NetUtils.get(Api.LOGOUT); var response = await NetUtils.get(Api.LOGOUT);
print('退出登陆 $response'); print('退出登陆 $response');
return response['success']; return response['success'];
} }
} }

View File

@ -17,12 +17,12 @@ class NetUtils {
var response; var response;
// 设置代理 便于本地 charles 抓包 // 设置代理 便于本地 charles 抓包
// (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
// (HttpClient client) { (HttpClient client) {
// client.findProxy = (uri) { client.findProxy = (uri) {
// return "PROXY 30.10.26.193:8888"; return "PROXY 30.10.29.190:8888";
// }; };
// }; };
Directory documentsDir = await getApplicationDocumentsDirectory(); Directory documentsDir = await getApplicationDocumentsDirectory();
String documentsPath = documentsDir.path; String documentsPath = documentsDir.path;

View File

@ -12,39 +12,52 @@ class _Page {
} }
final List<_Page> _allPages = <_Page>[ final List<_Page> _allPages = <_Page>[
_Page('项目1'), _Page('项目1'),
_Page('项目2'), _Page('项目2'),
_Page('项目3'), _Page('项目3'),
_Page('项目4'), _Page('项目4'),
]; ];
class MainPage extends StatelessWidget { class MainPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
print("MainPagess build......"); print("MainPagess build......");
return DefaultTabController( return DefaultTabController(
length: _allPages.length, length: _allPages.length,
child: Scaffold( child: Scaffold(
appBar: new MyAppBar( appBar: new MyAppBar(
leading: Container( leading: Container(
child: new ClipOval( child: new ClipOval(
child: Image.network( child: Image.network(
'https://hbimg.huabanimg.com/9bfa0fad3b1284d652d370fa0a8155e1222c62c0bf9d-YjG0Vt_fw658', 'https://hbimg.huabanimg.com/9bfa0fad3b1284d652d370fa0a8155e1222c62c0bf9d-YjG0Vt_fw658',
scale: 15.0, scale: 15.0,
), ),
) )),
),
centerTitle: true, centerTitle: true,
title: TabLayout(), title: TabLayout(),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.search), icon: Icon(Icons.search),
onPressed: () { onPressed: () {
pushPage(context, SearchPage(), pageName: "SearchPage"); pushPage(context, SearchPage(), pageName: "SearchPage");
}) })
], ],
), ),
body: TabBarViewLayout(), drawer: Drawer(
child: new ListView(
children: <Widget>[
new ListTile(
title: new Text("欢迎"),
),
new Divider(),
new ListTile(
title: new Text("设置"),
trailing: new Icon(Icons.settings),
onTap: () {}),
],
),
),
body: TabBarViewLayout(),
// drawer: Drawer( // drawer: Drawer(
// child: MainLeftPage(), // child: MainLeftPage(),
// ), // ),
@ -60,15 +73,12 @@ void pushPage(BuildContext context, Widget page, {String pageName}) {
class TabLayout extends StatelessWidget { class TabLayout extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return TabBar( return TabBar(
isScrollable: true, isScrollable: true,
//labelPadding: EdgeInsets.all(12.0), //labelPadding: EdgeInsets.all(12.0),
labelPadding: EdgeInsets.only(top: 12.0,left: 12.0,right:12.0), labelPadding: EdgeInsets.only(top: 12.0, left: 12.0, right: 12.0),
indicatorSize: TabBarIndicatorSize.label, indicatorSize: TabBarIndicatorSize.label,
tabs: _allPages tabs: _allPages.map((_Page page) => Tab(text: page.labelId)).toList(),
.map((_Page page) =>
Tab(text: page.labelId))
.toList(),
); );
} }
} }

View File

@ -1,9 +1,16 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:event_bus/event_bus.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_go/utils/data_utils.dart'; import 'package:flutter_go/utils/data_utils.dart';
import 'package:flutter_go/views/home.dart'; import 'package:flutter_go/views/home.dart';
import 'package:flutter_go/event/event_bus.dart';
import 'package:flutter_go/event/event_model.dart';
import 'package:flutter_go/model/user_info_cache.dart'; import 'package:flutter_go/model/user_info_cache.dart';
import 'package:flutter_go/routers/application.dart';
import 'package:flutter_go/routers/routers.dart';
class LoginPage extends StatefulWidget { class LoginPage extends StatefulWidget {
@override @override
@ -11,6 +18,11 @@ class LoginPage extends StatefulWidget {
} }
class _LoginPageState extends State<LoginPage> { class _LoginPageState extends State<LoginPage> {
_LoginPageState() {
final eventBus = new EventBus();
ApplicationEvent.event = eventBus;
}
// 利用FocusNode和_focusScopeNode来控制焦点 可以通过FocusNode.of(context)来获取widget树中默认的_focusScopeNode // 利用FocusNode和_focusScopeNode来控制焦点 可以通过FocusNode.of(context)来获取widget树中默认的_focusScopeNode
FocusNode _emailFocusNode = new FocusNode(); FocusNode _emailFocusNode = new FocusNode();
FocusNode _passwordFocusNode = new FocusNode(); FocusNode _passwordFocusNode = new FocusNode();
@ -47,27 +59,53 @@ class _LoginPageState extends State<LoginPage> {
} catch (err) { } catch (err) {
print('读取用户本地存储的用户信息出错 $err'); print('读取用户本地存储的用户信息出错 $err');
} }
ApplicationEvent.event.on<UserGithubOAuthEvent>().listen((event) {
if (event.isSuccess == true) {
print('请求接口');
// oAuth 认证成功
setState(() {
isLoading = true;
});
DataUtils.getUserInfo({'loginName': event.loginName}).then((result) {
print(result);
setState(() {
isLoading = false;
});
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => AppPage()),
(route) => route == null);
}).catchError((onError) {
print('获取身份信息 error:::$onError');
setState(() {
isLoading = false;
});
});
}
print('这是接受到的 event ${event.isSuccess} ${event.loginName}');
// _getList();
});
} }
// 创建登录界面的TextForm // 创建登录界面的TextForm
Widget buildSignInTextForm() { Widget buildSignInTextForm() {
return new Container( return Container(
decoration: new BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8)), borderRadius: BorderRadius.all(Radius.circular(8)),
), ),
width: MediaQuery.of(context).size.width * 0.8, width: MediaQuery.of(context).size.width * 0.8,
height: 190, height: 190,
// * Flutter提供了一个Form widget它可以对输入框进行分组然后进行一些统一操作如输入内容校验、输入框重置以及输入内容保存。 // * Flutter提供了一个Form widget它可以对输入框进行分组然后进行一些统一操作如输入内容校验、输入框重置以及输入内容保存。
child: new Form( child: Form(
key: _signInFormKey, key: _signInFormKey,
child: new Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 25, right: 25, top: 20, bottom: 20), left: 25, right: 25, top: 20, bottom: 20),
child: new TextFormField( child: TextFormField(
controller: _userNameEditingController, controller: _userNameEditingController,
//关联焦点 //关联焦点
focusNode: _emailFocusNode, focusNode: _emailFocusNode,
@ -78,14 +116,14 @@ class _LoginPageState extends State<LoginPage> {
_focusScopeNode.requestFocus(_passwordFocusNode); _focusScopeNode.requestFocus(_passwordFocusNode);
}, },
decoration: new InputDecoration( decoration: InputDecoration(
icon: new Icon( icon: Icon(
Icons.email, Icons.email,
color: Colors.black, color: Colors.black,
), ),
hintText: "Github 登录名", hintText: "Github 登录名",
border: InputBorder.none), border: InputBorder.none),
style: new TextStyle(fontSize: 16, color: Colors.black), style: TextStyle(fontSize: 16, color: Colors.black),
//验证 //验证
validator: (value) { validator: (value) {
if (value.isEmpty) { if (value.isEmpty) {
@ -100,7 +138,7 @@ class _LoginPageState extends State<LoginPage> {
), ),
), ),
), ),
new Container( Container(
height: 1, height: 1,
width: MediaQuery.of(context).size.width * 0.75, width: MediaQuery.of(context).size.width * 0.75,
color: Colors.grey[400], color: Colors.grey[400],
@ -108,18 +146,18 @@ class _LoginPageState extends State<LoginPage> {
Flexible( Flexible(
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 25, right: 25, top: 20), padding: const EdgeInsets.only(left: 25, right: 25, top: 20),
child: new TextFormField( child: TextFormField(
controller: _passwordEditingController, controller: _passwordEditingController,
focusNode: _passwordFocusNode, focusNode: _passwordFocusNode,
decoration: new InputDecoration( decoration: InputDecoration(
icon: new Icon( icon: Icon(
Icons.lock, Icons.lock,
color: Colors.black, color: Colors.black,
), ),
hintText: "Github 登录密码", hintText: "Github 登录密码",
border: InputBorder.none, border: InputBorder.none,
suffixIcon: new IconButton( suffixIcon: IconButton(
icon: new Icon( icon: Icon(
Icons.remove_red_eye, Icons.remove_red_eye,
color: Colors.black, color: Colors.black,
), ),
@ -128,7 +166,7 @@ class _LoginPageState extends State<LoginPage> {
), ),
//输入密码,需要用*****显示 //输入密码,需要用*****显示
obscureText: !isShowPassWord, obscureText: !isShowPassWord,
style: new TextStyle(fontSize: 16, color: Colors.black), style: TextStyle(fontSize: 16, color: Colors.black),
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return "密码不可为空!"; return "密码不可为空!";
@ -142,7 +180,7 @@ class _LoginPageState extends State<LoginPage> {
), ),
), ),
), ),
new Container( Container(
height: 1, height: 1,
width: MediaQuery.of(context).size.width * 0.75, width: MediaQuery.of(context).size.width * 0.75,
color: Colors.grey[400], color: Colors.grey[400],
@ -154,15 +192,15 @@ class _LoginPageState extends State<LoginPage> {
} }
Widget buildSignInButton() { Widget buildSignInButton() {
return new GestureDetector( return GestureDetector(
child: new Container( child: Container(
padding: EdgeInsets.only(left: 42, right: 42, top: 10, bottom: 10), padding: EdgeInsets.only(left: 42, right: 42, top: 10, bottom: 10),
decoration: new BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5)), borderRadius: BorderRadius.all(Radius.circular(5)),
color: Theme.of(context).primaryColor), color: Theme.of(context).primaryColor),
child: new Text( child: Text(
"LOGIN", "LOGIN",
style: new TextStyle(fontSize: 25, color: Colors.white), style: TextStyle(fontSize: 25, color: Colors.white),
), ),
), ),
onTap: () { onTap: () {
@ -186,7 +224,9 @@ class _LoginPageState extends State<LoginPage> {
}); });
DataUtils.doLogin({'username': username, 'password': password}) DataUtils.doLogin({'username': username, 'password': password})
.then((result) { .then((result) {
print(result); if(result.runtimeType == String){
throw result;
}
setState(() { setState(() {
isLoading = false; isLoading = false;
}); });
@ -198,20 +238,28 @@ class _LoginPageState extends State<LoginPage> {
.then((value) { .then((value) {
// print('存储成功:$value'); // print('存储成功:$value');
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(
new MaterialPageRoute(builder: (context) => AppPage()), MaterialPageRoute(builder: (context) => AppPage()),
(route) => route == null); (route) => route == null);
}); });
}); });
} catch (err) { } catch (err) {
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(
new MaterialPageRoute(builder: (context) => AppPage()), MaterialPageRoute(builder: (context) => AppPage()),
(route) => route == null); (route) => route == null);
} }
}).catchError((onError) { }).catchError((errorMsg) {
print(onError);
setState(() { setState(() {
isLoading = false; isLoading = false;
}); });
Fluttertoast.showToast(
msg: errorMsg.toString(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIos: 1,
backgroundColor: Theme.of(context).primaryColor,
textColor: Colors.white,
fontSize: 16.0
);
}); });
} }
@ -275,7 +323,27 @@ class _LoginPageState extends State<LoginPage> {
), ),
buildSignInTextForm(), buildSignInTextForm(),
buildSignInButton(), buildSignInButton(),
SizedBox(height: 35.0), SizedBox(height: 15.0),
new Container(
height: 1,
width: MediaQuery.of(context).size.width * 0.75,
color: Colors.grey[400],
margin: const EdgeInsets.only(bottom: 10.0),
),
FlatButton(
child: Text(
'Github OAuth 认证',
style: TextStyle(
color: Theme.of(context).primaryColor,
decoration: TextDecoration.underline),
),
onPressed: () {
// _launchURL('https://github.com/login/oauth/authorize?client_id=cfe4795e76382ae8a5bd&scope=user,public_repo');
Application.router.navigateTo(context,
'${Routes.webViewPage}?title=Github&url=${Uri.encodeComponent("https://github.com/login/oauth/authorize?client_id=cfe4795e76382ae8a5bd&scope=user,public_repo")}');
},
)
], ],
), ),
Positioned( Positioned(

View File

@ -1,5 +1,5 @@
/// @Author: 一凨 /// @Author: 一凨
/// @Date: 2019-01-14 17:44:47 /// @Date: 2019-01-14 17:44:47
/// @Last Modified by: 一凨 /// @Last Modified by: 一凨
/// @Last Modified time: 2019-01-14 19:47:14 /// @Last Modified time: 2019-01-14 19:47:14
@ -11,6 +11,7 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:flutter_go/model/collection.dart'; import 'package:flutter_go/model/collection.dart';
import 'package:flutter_go/event/event_bus.dart'; import 'package:flutter_go/event/event_bus.dart';
import 'package:flutter_go/event/event_model.dart'; import 'package:flutter_go/event/event_model.dart';
import 'package:flutter_go/api/api.dart';
class WebViewPage extends StatefulWidget { class WebViewPage extends StatefulWidget {
final String url; final String url;
@ -21,6 +22,7 @@ class WebViewPage extends StatefulWidget {
} }
class _WebViewPageState extends State<WebViewPage> { class _WebViewPageState extends State<WebViewPage> {
final flutterWebviewPlugin = new FlutterWebviewPlugin();
bool _hasCollected = false; bool _hasCollected = false;
String _router = ''; String _router = '';
var _collectionIcons; var _collectionIcons;
@ -30,6 +32,24 @@ class _WebViewPageState extends State<WebViewPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
flutterWebviewPlugin.onUrlChanged.listen((String url) {
print('url change:$url');
if (url.indexOf('${Api.RedirectIp}loginSuccess') == 0) {
String loginName = url.substring(url.indexOf('=') + 1);
if (ApplicationEvent.event != null) {
ApplicationEvent.event.fire(UserGithubOAuthEvent(loginName, true));
}
flutterWebviewPlugin.close();
// 验证成功
} else if (url.indexOf('${Api.RedirectIp}loginFail') == 0) {
// 验证失败
if (ApplicationEvent.event != null) {
ApplicationEvent.event.fire(UserGithubOAuthEvent('', true));
}
flutterWebviewPlugin.close();
}
// if(url == '${Api.RedirectIp}loginSuccess')
});
_collectionControl _collectionControl
.getRouterByName(Uri.encodeComponent(widget.title.trim())) .getRouterByName(Uri.encodeComponent(widget.title.trim()))
.then((list) { .then((list) {
@ -98,7 +118,7 @@ class _WebViewPageState extends State<WebViewPage> {
_collectionIcons = Icons.favorite_border; _collectionIcons = Icons.favorite_border;
} }
return Scaffold( return Scaffold(
key: _scaffoldKey, key: _scaffoldKey,
appBar: AppBar( appBar: AppBar(
title: Text(widget.title), title: Text(widget.title),
actions: <Widget>[ actions: <Widget>[

View File

@ -144,6 +144,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.3.4" version: "0.3.4"
fluttertoast:
dependency: "direct main"
description:
name: fluttertoast
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
html: html:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -29,6 +29,7 @@ dependencies:
shared_preferences: ^0.4.3 shared_preferences: ^0.4.3
flutter_spinkit: "^3.1.0" flutter_spinkit: "^3.1.0"
path_provider: ^1.0.0 path_provider: ^1.0.0
fluttertoast: ^3.1.0
dio: ^2.0.15 dio: ^2.0.15
flutter_webview_plugin: ^0.3.4 flutter_webview_plugin: ^0.3.4
cookie_jar: ^1.0.0 cookie_jar: ^1.0.0